How to convert flat PHP array to indexed array - php

I have the following array:
'values' => [
'protein_question_0_typing_method' => '38'
'protein_question_0_amount_1' => '1'
'protein_question_0_amount_2' => '2'
'protein_question_0_units_of_measurement' => '17'
'protein_question_1_typing_method' => '39'
'protein_question_1_amount_1' => '2'
'protein_question_1_amount_2' => '2'
'protein_question_1_units_of_measurement' => '17'
'protein_question_2_typing_method' => '42'
'protein_question_2_amount_1' => '2'
'protein_question_2_amount_2' => '2'
'protein_question_2_units_of_measurement' => '17'
'distributionId' => '21'
]
How would I convert into a structure like this?
'values' => [
0 => [
'protein_question_typing_method' => '38',
'protein_question_amount_1' => '1',
'protein_question_amount_2' => '2'
],
1 => [
'protein_question_typing_method' => '42',
'protein_question_amount_1' => '1',
'protein_question_amount_2' => '2'
],
...
'distributionId' => '21'
]
This is what I've tried:
$params = \Yii::$app->request->post();
$length = count($params['values']);
for($i = 0; $i < $length; $i++) {
if(!empty($params['values']['protein_question_' . $i . '_typing_method'])) {
echo $params['values']['protein_question_' . $i . '_typing_method'] . "<br /><hr />";
}
}
The above code just prints the data, the reason I need it in the chunked format is because each chunk will be saved as a new model record in the DB.
So basically just need to convert it to an index array, anyone know the easiest way to do this as looping over the first array would be complicated?
Thanks

Can do
$input = [
'values' => [
'protein_question_0_typing_method' => '38',
'protein_question_0_amount_1' => '1',
'protein_question_0_amount_2' => '2',
'protein_question_0_units_of_measurement' => '17',
'protein_question_1_typing_method' => '39',
'protein_question_1_amount_1' => '2',
'protein_question_1_amount_2' => '2',
'protein_question_1_units_of_measurement' => '17',
'protein_question_2_typing_method' => '42',
'protein_question_2_amount_1' => '2',
'protein_question_2_amount_2' => '2',
'protein_question_2_units_of_measurement' => '17',
'distributionId' => '21'
]
];
$output = [];
foreach ($input["values"] as $key => $value) {
if (preg_match('#^protein_question_(\d+)_(.+)$#', $key, $match)) {
$output[$match[1]]['protein_question_' . $match[2]] = $value;
} else {
$output[$key] = $value;
}
}
var_dump($output);
This will iterate over all the keys in the array and match if the start with protein_question, followed by a number, followed by some text. If so, the number is used as the index in the output to hold the key minus the number along with the value. If it doesnt match, the key and value are put as is.
Will give
array(4) {
[0]=>
array(4) {
["protein_question_typing_method"]=>
string(2) "38"
["protein_question_amount_1"]=>
string(1) "1"
["protein_question_amount_2"]=>
string(1) "2"
["protein_question_units_of_measurement"]=>
string(2) "17"
}
[1]=>
array(4) {
["protein_question_typing_method"]=>
string(2) "39"
["protein_question_amount_1"]=>
string(1) "2"
["protein_question_amount_2"]=>
string(1) "2"
["protein_question_units_of_measurement"]=>
string(2) "17"
}
[2]=>
array(4) {
["protein_question_typing_method"]=>
string(2) "42"
["protein_question_amount_1"]=>
string(1) "2"
["protein_question_amount_2"]=>
string(1) "2"
["protein_question_units_of_measurement"]=>
string(2) "17"
}
["distributionId"]=>
string(2) "21"
}

Here a very basic implementation to get you started, you may want to adjust it to your specific needs:
<?php
$values = [
'protein_question_0_typing_method' => '38',
'protein_question_0_amount_1' => '1',
'protein_question_0_amount_2' => '2',
'protein_question_0_units_of_measurement' => '17',
'protein_question_1_typing_method' => '39',
'protein_question_1_amount_1' => '2',
'protein_question_1_amount_2' => '2',
'protein_question_1_units_of_measurement' => '17',
'protein_question_2_typing_method' => '42',
'protein_question_2_amount_1' => '2',
'protein_question_2_amount_2' => '2',
'protein_question_2_units_of_measurement' => '17',
'distributionId' => '21'
];
function convert($values) {
$result = [];
foreach ($values as $key => $value) {
$matches = [];
$ret = preg_match('~^protein_question_([0-9]+)_~U', $key, $matches);
// Key does not match the pattern protein_question_*_
if ($ret !== 1) {
$result[$key] = $value;
continue;
}
$proteinQuestionID = (int)$matches[1];
// Create key for the this ID
if (!isset($result[$proteinQuestionID])) {
$result[$proteinQuestionID] = [];
}
// Adjust the key...
$key = \substr($key, \strlen('protein_question_'.$proteinQuestionID));
$key = 'protein_question'.$key;
// Append to it...
$result[$proteinQuestionID][$key] = $value;
}
return $result;
}
print_r(convert($values));

did you tried array_chunk($your_array, 4) . it looks this method can help you

Related

Comparing 2 Arrays using array_map?

I wanted to refrain from using nested foreach in my actual code, so I was thinking of using an array function (correct me if I'm wrong) called array_walk thinking it would replace my code in foreach.
I wanted to compare both of the WHOLE array if they one of them have the same description, but the problem is array_walk only compares the first key/index and does not go through the second index to check. is there other way? I'm just trying to optimize my code
By the way, this code returns both found
<?php $array = array (
'1' => array(
'count' => '1',
'id' => 1,
'description' => 'Bag',
),
'2' => array(
'count' => '1',
'id' => 2,
'description' => 'Pencil',
), );
$bin = array (
'1' => array(
'count' => '1',
'id' => 2,
'description' => 'Bag',
),
'2' => array(
'count' => '1',
'id' => 2,
'description' => 'Pencil',
), );
$b = array_map(function($array, $bin) {
if ($array['description'] == $bin['description']){
$count = "found";
}else{
$count = "not found";
}
return array("status" => $count, "cart_array" => $array['description'], "bin"=>$bin['description']); }, $array, $bin);
var_dump($b);
?>
but this one, the first array doesnt return found, it should return
found because there is a pencil and bag in $bin array updated the code
<?php
$array = array (
'1' => array(
'count' => '1',
'id' => 1,
'description' => 'Bag',
),
'2' => array(
'count' => '1',
'id' => 2,
'description' => 'Pencil',
),
);
$bin = array (
'1' => array(
'count' => '1',
'id' => 2,
'description' => 'Pencil',
),
'2' => array(
'count' => '1',
'id' => 2,
'description' => 'Bag',
),
);
$b = array_map(function($array, $bin)
{
if ($array['description'] == $bin['description']){
$count = "found";
}else{
$count = "not found";
}
return array("status" => $count, "cart_array" => $array['description'], "bin"=>$bin['description']);
}, $array, $bin);
var_dump($b);
?>
Use array_column first to get all of description keys from $array. Then, you can check these values with $bin values.
$desc = array_column($array, 'description');
$b = array_map(function($array, $bin)
{
global $desc;
if (in_array($bin['description'], $desc)){
$count = "found";
}else{
$count = "not found";
}
return array("status" => $count, "cart_array" => $array['description'], "bin" => $bin['description']);
}, $array, $bin);
var_dump($b);
You don't have any expected output in the question but I assume you want to know the difference between them.
In the manual for array_diff there is a code called arrayRecursiveDiff which handles multidimensional arrays and outputs the difference.
var_dump(arrayRecursiveDiff($array, $bin));
function arrayRecursiveDiff($aArray1, $aArray2) {
$aReturn = array();
foreach ($aArray1 as $mKey => $mValue) {
if (array_key_exists($mKey, $aArray2)) {
if (is_array($mValue)) {
$aRecursiveDiff = arrayRecursiveDiff($mValue, $aArray2[$mKey]);
if (count($aRecursiveDiff)) { $aReturn[$mKey] = $aRecursiveDiff; }
} else {
if ($mValue != $aArray2[$mKey]) {
$aReturn[$mKey] = $mValue;
}
}
} else {
$aReturn[$mKey] = $mValue;
}
}
return $aReturn;
}
This outputs:
array(2) {
[1]=>
array(2) {
["id"]=>
int(1)
["description"]=>
string(3) "Bag"
}
[2]=>
array(1) {
["description"]=>
string(6) "Pencil"
}
}
You can use this.Nevertheless both arrays have different length or the values do not have the same position, This will work :
$bin_desc=array_column($bin,'description');
$b = array_map(function($array)use($bin_desc) {
if (in_array($array['description'],$bin_desc)){
$count = "found";
}else{
$count = "not found";
}
return array("status" => $count, "cart_array" => $array['description'], "bin"=>$array['description']); }, $array);
var_dump($b);

Recursion with multidimensional array

I have been working on this for long and I got it working as I want but I think there is simpler solution.
So far I got this:
$menu = array(
0 => (object) array(
'cat_id' => 1,
'cat_parent' => 0,
'cat_name' => 'domov',
'cat_href' => 'domov',
'cat_subcategories' => array()
),
1 => (object) array(
'cat_id' => 2,
'cat_parent' => 0,
'cat_name' => 'clanky',
'cat_href' => 'clanky',
'cat_subcategories' => array(
0 => (object) array(
'cat_id' => 9,
'cat_parent' => 2,
'cat_name' => 'apple clanky',
'cat_href' => 'apple',
'cat_subcategories' => array(
0 => (object) array(
'cat_id' => 11,
'cat_parent' => 9,
'cat_name' => 'iphone clanky',
'cat_href' => 'iphone',
'cat_subcategories' => array()
),
1 => (object) array(
'cat_id' => 12,
'cat_parent' => 9,
'cat_name' => 'macbook clanky',
'cat_href' => 'macbook',
'cat_subcategories' => array()
)
)
),
1 => (object) array(
'cat_id' => 10,
'cat_parent' => 2,
'cat_name' => 'microsoft clanky',
'cat_href' => 'microsoft',
'cat_subcategories' => array()
),
)
),
2 => (object) array(
'cat_id' => 3,
'cat_parent' => 0,
'cat_name' => 'produkty',
'cat_href' => 'produkty',
'cat_subcategories' => array()
),
3 => (object) array(
'cat_id' => 4,
'cat_parent' => 0,
'cat_name' => 'vyrobcovia',
'cat_href' => 'vyrobcovia',
'cat_subcategories' =>
array(
0 => (object) array(
'cat_id' => 5,
'cat_parent' => 4,
'cat_name' => 'apple',
'cat_href' => 'apple',
'cat_subcategories' => array(
0 => (object) array(
'cat_id' => 7,
'cat_parent' => 5,
'cat_name' => 'iphone',
'cat_href' => 'iphone',
'cat_subcategories' => array()
),
1 => (object) array(
'cat_id' => 8,
'cat_parent' => 5,
'cat_name' => 'macbook',
'cat_href' => 'macbook',
'cat_subcategories' => array()
)
)
),
1 => (object) array(
'cat_id' => 6,
'cat_parent' => 4,
'cat_name' => 'microsoft',
'cat_href' => 'microsoft',
'cat_subcategories' => array()
),
)
),
);
function generate_menu($menu, $level = 1, $tmp_array = array())
{
foreach($menu as $key => $c)
{
$menu_item = get_menu_elements($c, $level);
$tmp_array = array_replace_recursive($tmp_array, $menu_item);
foreach($c->cat_subcategories as $_key => $_c)
{
$menu_item = get_menu_elements($_c, $level+1);
$tmp_array = array_replace_recursive($tmp_array, $menu_item);
foreach($_c->cat_subcategories as $__key => $__c)
{
$menu_item = get_menu_elements($__c, $level+2);
$tmp_array = array_replace_recursive($tmp_array, $menu_item);
}
}
}
return $tmp_array;
}
function get_menu_elements($c, $level = 1)
{
$level_var = "level_".($level);
$output = array(
$level_var => array()
);
$output[$level_var][$c->cat_id] = array(
'parent' => $c->cat_parent,
'html' => $c->cat_name
);
return $output;
}
In the end I should have multidimensional array with:
array(3) {
["level_1"]=>
array(4) {
[1]=>
array(2) {
["parent"]=>
int(0)
["html"]=>
string(5) "domov"
}
[2]=>
array(2) {
["parent"]=>
int(0)
["html"]=>
string(6) "clanky"
}
[3]=>
array(2) {
["parent"]=>
int(0)
["html"]=>
string(8) "produkty"
}
[4]=>
array(2) {
["parent"]=>
int(0)
["html"]=>
string(10) "vyrobcovia"
}
}
["level_2"]=>
array(4) {
[9]=>
array(2) {
["parent"]=>
int(2)
["html"]=>
string(12) "apple clanky"
}
[10]=>
array(2) {
["parent"]=>
int(2)
["html"]=>
string(16) "microsoft clanky"
}
[5]=>
array(2) {
["parent"]=>
int(4)
["html"]=>
string(5) "apple"
}
[6]=>
array(2) {
["parent"]=>
int(4)
["html"]=>
string(9) "microsoft"
}
}
["level_3"]=>
array(4) {
[11]=>
array(2) {
["parent"]=>
int(9)
["html"]=>
string(13) "iphone clanky"
}
[12]=>
array(2) {
["parent"]=>
int(9)
["html"]=>
string(14) "macbook clanky"
}
[7]=>
array(2) {
["parent"]=>
int(5)
["html"]=>
string(6) "iphone"
}
[8]=>
array(2) {
["parent"]=>
int(5)
["html"]=>
string(7) "macbook"
}
}
}
I want to print multi-level menu recursion. I got it working with this code but in function generate_menu I had to use 3 foreach loops for cat_subcategories. When I used recursion like this:
function generate_menu($menu, $level = 1, $tmp_array = array())
{
foreach($menu as $key => $c)
{
$menu_item = get_menu_elements($c, $level);
$tmp_array = array_replace_recursive($tmp_array, $menu_item);
if (!empty($c->cat_subcategories)) generate_menu($c->cat_subcategories, $level + 1, $tmp_array);
}
return $tmp_array;
}
i got only 'level_1' in output
The output which I am getting now is the same I want I just want to simplify the multiple foreach()
etc. Basicaly
level_1 - first loop of $menu
level_2 - loop of cat_subcategories
level_3 - loop of cat_subcategories for cat_subcategories item
You essentially need to perform a breadth-first traversal in your menu tree. For that I would suggest an iterative function instead of a recursive function, as the latter is more suitable for a depth-first traversal.
Here is the function:
function generate_menu($menu) {
$result = [];
$level = 1;
while (count($menu)) {
$queue = [];
$items = [];
foreach($menu as $cat) {
$items[$cat->cat_id] = [
"parent" => $cat->cat_parent,
"html" => $cat->cat_name
];
$queue = array_merge($queue, $cat->cat_subcategories);
}
$result["level_$level"] = $items;
$level++;
$menu = $queue;
}
return $result;
}
See it run on eval.in.
As this function traverses the top level of the tree, it collects all the children into $queue. Once the top level has been translated into the output (in the level_1 key), that queue will have all second level entries. This then is moved to $menu, and the process is repeated, but now with level_2. This continues until a level is reached where no more entries are found.
I've made some time ago this function. It could help you.
I've got an array where $arr[actual item][parental id]
function getChild($id, $result, $count) {
for( $i = 0; $i < sizeof($result); $i ++) {
if( $result[$i][2] == $id) {
getChild($result[$i][0], $result, $count + 1);
}
}
}
EDIT
In my case, where all the items in the one-dimensional array, but with the hierarchy of n-dimensional array depended on the parental id.
CODE TO PRINT MENU
This code will work for N-number of hierarchy
static function printAllCategoriesAsCheckbox($arr, $d=0){
$htmlString = "";
if (is_array($arr)){
foreach($arr as $category){
$htmlString = $htmlString . '<div><input style="margin-left: ' . 30*$d . 'px;" value="'.$category->id.'" class="category-input" type="checkbox" name="category_id[]">';
$htmlString = $htmlString . ' <label for="category_'.$category->id.'">' . $category->name . '</label></div>';
if (is_array($category['childs'])){
$htmlString = $htmlString . ItemCategory::printAllCategoriesAsCheckbox($category['childs'], $d+1);
}
}
}
return $htmlString;
}

Adding another dimension to array

I have an array of TLDs and prices, and now I want to be able to add a classification i.e. 'Australian','New Zealand','Industry' to the domains but I am having troubles adding the extra dimension.
The array I have is
$domains = array(
'.com.au' => '19.98',
'.melbourne' => '90.00',
'.academy' => '45.00',
'.accountants' => '120.00',
'.ac.nz' => '36.75');
$domains = array(
'.com.au' => array(
'country' => 'Australia',
'sector' => 'Industry',
'price' => '19.98'
),
);
Is this a beginning on what you're looking for ?
Is this code ok for you?
<?php
$domains = array(
'.com.au' => '19.98',
'.melbourne' => '90.00',
'.academy' => '45.00',
'.accountants' => '120.00',
'.ac.nz' => '36.75');
$newDomains = [];
foreach($domains as $key=>$value){
if($key == '.com.au'){
$newDomains[$key]['TLD'] = $value;
$newDomains[$key]['Industry'] = 'blabal';
}else{
$newDomains[$key] = $value;
}
}
echo '<pre>';
var_dump($newDomains);
echo '</pre>';
?>
Or even:
$domains = array(
'.com.au' => '19.98',
'.melbourne' => '90.00',
'.academy' => '45.00',
'.accountants' => '120.00',
'.ac.nz' => '36.75');
$industryArray = array(
'.com.au' => 'blabla'
);
$newDomains = [];
foreach($domains as $key=>$value){
if(isset($industryArray[$key])){
$newDomains[$key]['TLD'] = $value;
$newDomains[$key]['Industry'] = $industryArray[$key];
}else{
$newDomains[$key] = $value;
}
}
echo '<pre>';
var_dump($newDomains);
echo '</pre>';
The result is:
array(5) {
[".com.au"]=>
array(2) {
["TLD"]=>
string(5) "19.98"
["Industry"]=>
string(6) "blabla"
}
[".melbourne"]=>
string(5) "90.00"
[".academy"]=>
string(5) "45.00"
[".accountants"]=>
string(6) "120.00"
[".ac.nz"]=>
string(5) "36.75"
}

Combine array elements

I want to loop through 3 arrays to create 1 single array with all 3 values in them.
See below for example and outcome.
Input:
array(
'0' => array(
'0' => array('a'),
'1' => array('b')
),
'1' => array(
'0' => array('c'),
'1' => array('d'),
'2' => array('e')
),
'2' => array(
'0' => array('f')
),
)
Outcome:
array(
'0' => 'acf',
'1' => 'adf',
'2' => 'aef',
'3' => 'bcf',
'4' => 'bdf',
'5' => 'bef'
)
Funnily I had the same problem a couple of years ago, so here's the solution I then came up with.
public static function combineElementsSuccessive($arry)
{
$result = [];
if (empty($arry) || !is_array($arry)) {
return result;
}
self::concatAndPush('', $result, $arry, 0);
return $result;
}
private static function concatAndPush($str, &$res_arry, $arry, $index)
{
foreach ($arry[$index] as $key => $val) {
$mod_str = $str . $val;
if (isset($arry[$index+1])) {
self::concatAndPush($mod_str, $res_arry, $arry, $index+1);
}
else {
$res_arry[] = $mod_str;
}
}
}
See it in action
Nevermind the static methods, I had to integrate them somehow in an application full of legacy code ;-)
How about this?
// $old_array = your original array
$new_array=array();
for ($i=0; $i<count($old_array[0]); $i++) {
for ($j=0; $j<count($old_array[1]); $j++) {
for ($k=0; $k<count($old_array[2]); $k++) {
$new_array[]=$old_array[0][$i].$old_array[1][$j].$old_array[2][$k];
}
}
}
var_dump($new_array);
It returns:
array(6) { [0]=> string(3) "acf" [1]=> string(3) "adf" [2]=> string(3) "aef" [3]=> string(3) "bcf" [4]=> string(3) "bdf" [5]=> string(3) "bef" }
Convert your array as following numbers array and run the code
$numbers = array(
array("a", "b"),
array("c", "d", "e"),
array("f"),
);
$f_nb = $numbers['0'];
$s_nb = $numbers['1'];
$t_nb = $numbers['2'];
$final_array = array();
for($a = 0; $a<sizeof($f_nb); $a++)
{
for($b = 0; $b<sizeof($s_nb); $b++)
{
for($c = 0; $c<sizeof($t_nb); $c++)
{
$final_array[] = $f_nb["$a"] . $s_nb["$b"] . $t_nb["$c"];
}
}
}
print_r($final_array);
Try this:
$array = array(
'0' => array(
'0' => array('a'),
'1' => array('b')
),
'1' => array(
'0' => array('c'),
'1' => array('d'),
'2' => array('e')
),
'2' => array(
'0' => array('f')
),
);
$outcome = array();
foreach ($array['0'] as $key => $value1)
{
foreach ($array['1'] as $value2)
{
foreach ($array['2'] as $value3)
{
$outcome[] = $value1[0].$value2[0].$value3[0];
}
}
}
print_r($outcome);

PHP $_POST data into Variable

I have following $_POST data from the form fieldset
array(2) {
["item-1"] =>
array(2) {
["name"]=> string(5) "apple"
["price"]=> string(1) "5"
}
["item-2"] =>
array(2) {
["name"]=> string(6) "orange"
["price"]=> string(1) "2"
}
}
I want to store this post data into variables using foreach such as $name_1 $price_1 & $name_2 $price_2
How can I parse this form-data ?
Altough I think it's completely unlogical to use variables this way, this can help you out.
It created the variables automatically using the given information..
//array with values
$source = [
'item-1' => [
'name' => 'apple',
'price' => '5',
],
'item-2' => [
'name' => 'orange',
'price' => '2'
]
];
foreach($source as $k=>$array) {
//get all integer values from the key
$int = preg_replace('/[^0-9]/', '', $k);
//foreach property in $array, create the variable name + the integer number
//as a variable and set the value belonging to the key
foreach($array as $name=>$value) {
${$name . '_' . $int} = $value;
}
}
$i = 1;
foreach($_POST as $data) {
${'name_' . $i} = $data["name"];
${'price_' . $i} = $data["price"];
$i++;
}
foreach ($_POST as $k => $v) {
$i = +preg_replace('/item-(\d+)/', '$1', $k);
foreach(array('name', 'price') as $name) {
$key = "$name_$i";
$$key = $v[$name];
}
Hope it helps.
Try this..
<?php
$response =
array(
'item-1' => array(
2 => array(
'name' => 'apple',
'price' => 5
),
),
'item-2' => array(
2 => array(
'name' => 'orange',
'price' => 2
),
),
);
foreach($response as $key =>$value)
{
$k=explode("-",$key);
$keyvalue=end($k);
foreach($value as $result)
{
echo ${'name_' . $keyvalue}=$result['name'];
echo "</br>";
echo ${'price_' . $keyvalue}=$result['price'];
echo "</br>";
}
}
?>

Categories