Combine Arrays into One Multidimensional Array using PHP - php

I am trying to combine arrays into one single multidimensional array. There could be more than 5 arrays that needs to be combined so I need a code that will automatically combine all arrays no matter how many they are. I tried array_merge but it requires manual defining of arrays in comma formatted parameters.
The code to convert is:
Array
(
[id] => 1
[name] => Item 1
[slug] => item-slug-1
[parent] => 0
)
Array
(
[id] => 2
[name] => Item 2
[slug] => item-slug-2
[parent] => 1
)
Array
(
[id] => 3
[name] => Item 3
[slug] => item-slug-3
[parent] => 2
)
Array
(
[id] => 4
[name] => Item 4
[slug] => item-slug-4
[parent] => 3
)
Array
(
[id] => 5
[name] => Item 5
[slug] => item-slug-5
[parent] => 3
)
And this is how I would like it to look:
Array
(
[0] => Array
{
[id] => 1
[name] => Item 1
[slug] => item-slug-1
[parent] => 0
}
[1] => Array
{
[id] => 2
[name] => Item 2
[slug] => item-slug-2
[parent] => 1
}
[2] => Array
{
[id] => 3
[name] => Item 3
[slug] => item-slug-3
[parent] => 2
}
[3] => Array
{
[id] => 4
[name] => Item 4
[slug] => item-slug-4
[parent] => 3
}
[4] => Array
{
[id] => 5
[name] => Item 5
[slug] => item-slug-5
[parent] => 3
}
)
Here is how the arrays are generated:
I receive a response JSON from the server that looks like this:
[{"slug":"item-slug-1","name":"Item 1","id":1},{"slug":"item-slug-2","name":"Item 2","id":2},{"slug":"item-slug-3","name":"Item 3","id":3,"children":[{"slug":"item-slug-4","name":"Item 4","id":4},{slug":"item-slug-5","name":"Item 5","id":5}]}]
I decode the JSON then convert it to an array like this:
$categories_obj = json_decode( $_POST['order'] );
$categories_arr = json_decode(json_encode( $categories_obj ), true);
I created a function that walks through each item so it would be easier to insert into my database:
function walk_and_update($data, $parent = 0, $count = 0) {
if( is_array($data) ) {
$combine = array();
/* The arrays are generated here */
foreach( $data as $key => $row ) {
$formatted = array(
'id' => $row['id'],
'name' => $row['name'],
'slug' => $row['slug'],
'parent' => $parent
);
print_r( $formatted );
/* My SQL update is here */
if( isset( $row['children'] ) ) {
walk_and_update( $row['children'], $row['id'], $count );
}
}
}
}
Then I use the function like this:
walk_and_update( $categories_arr );

Like this:
$arr1 = Array(
'id' => 1,
'name' => 'Item 1',
'slug' => 'item-slug-1',
'parent' => 0);
$arr2 = Array(
'id' => 2,
'name' => 'Item 2',
'slug' => 'item-slug-2',
'parent' => 1);
$arr3 = Array(
'id' => 3,
'name' => 'Item 3',
'slug' => 'item-slug-3',
'parent' => 2);
$new_arr = array();
for($i=1;$i<=3;$i++) {
$var_name = 'arr'.$i;
array_push($new_arr,$$var_name);
}
echo "<pre>";print_r($new_arr);
Output:
Array
(
[0] => Array
(
[id] => 1
[name] => Item 1
[slug] => item-slug-1
[parent] => 0
)
[1] => Array
(
[id] => 2
[name] => Item 2
[slug] => item-slug-2
[parent] => 1
)
[2] => Array
(
[id] => 3
[name] => Item 3
[slug] => item-slug-3
[parent] => 2
)
)

you could make function to handle the array, then return expected array to multidimensional array.
can i know first, that the array you want to merging , did they produce one by one or just one time that can produce many array ?
//you could do this if your array produces one time only
$counter = 0;
$new_array=array();
foreach (your array as $key => $val)
{
$new_array[$counter]['id']= $val['id'];
$new_array[$counter]['name']= $val['name'];
$new_array[$counter]['slug']= $val['slug'];
$new_array[$counter]['parent'] = $val['parent'];
$counter++;
}
//if your array produces more than one time
function main ()
{
$data['counter']=0;
$data['newarray']=array();
$data = $this->mergin_array(your array,$data['counter'])
}
function merging_array(your array,$counter)
{
$data = array();
$counter_new = $counter;
foreach(your array as $key => $val)
{
$data['newarray'][$counter]['id'] = $val['id'];
$data['newarray'][$counter]['name'] = $val['name'];
$data['newarray'][$counter]['slug'] = $val['slug'];
$data['newarray'][$counter]['parent'] = $val['parent'];
$counter_new++;
}
$data['counter'] = $counter_new;
return $data;
}
so no matter how many you use , when you access the $data['newarray'] in your main function it will get you the combined for many array

Related

Sort all child by parent id

i have array like this:
(
[0] => Array
(
[id] => 1
[name] => Bazowa
[parent_id] => 0
)
[1] => Array
(
[id] => 2
[name] => Główna
[parent_id] => 1
)
[2] => Array
(
[id] => 12
[name] => PlayStation
[parent_id] => 2
)
[3] => Array
(
[id] => 13
[name] => Xbox
[parent_id] => 2
)
[4] => Array
(
[id] => 14
[name] => Nintendo
[parent_id] => 2
)
[5] => Array
(
[id] => 15
[name] => PC
[parent_id] => 2
)
)
and i want sort this array like tree on screenshot below:
Screen of tree what I want
i trying use this Sort array values based on parent/child relationship
foreach($xml->children()->children() as $value) {
if($value->active == 1) {
$categories[] = [
'id' => (int) $value->id,
'name' => (string) $value->name->language,
'parent_id' => (int) $value->id_parent
];
}
}
$parent_ids = [];
$parents = ['' => []];
foreach($categories as $val) {
$parents[$val['parent_id']][] = $val;
}
$sorted = $parents[''];
dump($parents); exit;
for($val = reset($sorted); $val; $val = next($sorted)) {
if(isset($parents[$val[0]])) {
foreach($parents[$val[0]] as $next) {
$sorted[] = $next;
}
}
}
The most important thing for me is that everything displays well in select, which is something like this:
-Playstation
-- Playstation 5
--- Gry
--Playstation 3
--- Gry
Anyone can help me?
EDIT:
Problem solved by Build a tree from a flat array in PHP
This should work
usort($arr, function($a, $b) {
return $a["parent_id"] > $b["parent_id"];
});

How to 'flatten' a multi dimensional array of unknown depth and length AND record it's parent-child relations? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have a PHP array that looks like this:
Array
(
[0] => Array
(
[id] => 2
[name] => Item2
[children] => Array
(
[0] => Array
(
[id] => 1
[name] => Item1
[children] => Array
(
[0] => Array
(
[id] => 5
[name] => Item5
)
)
)
[1] => Array
(
[id] => 4
[name] => Item4
)
)
)
[1] => Array
(
[id] => 3
[name] => Item3
)
)
It has unknown (unpredictable) depth and length. Any item on any level may or may not have children. It has been created from an xml file that contains product groups. I would like to convert it to an array that contains arrays of three elements: id, name, and parent id:
[0] => array('id' => '2', 'name' => 'Item2', 'parent' => 0),
[1] => array('id' => '1', 'name' => 'Item1', 'parent' => 2),
[2] => array('id' => '4', 'name' => 'Item4', 'parent' => 2) etc.
How can I do it?
Thank you!
This can be achieved with a recursive function that pushes all the items from a given level of the array, then calls itself for any children arrays:
function list_items($array, $parent = 0) {
$output = array();
foreach ($array as $arr) {
$output[] = array('id' => $arr['id'], 'name' => $arr['name'], 'parent' => $parent);
if (is_array($arr['children'] ?? NULL)) {
$output = array_merge($output, list_items($arr['children'], $arr['id']));
}
}
return $output;
}
$items = list_items($array);
Output (for my slightly expanded data):
Array
(
[0] => Array
(
[id] => 2
[name] => Item2
[parent] => 0
)
[1] => Array
(
[id] => 1
[name] => Item1
[parent] => 2
)
[2] => Array
(
[id] => 5
[name] => Item5
[parent] => 1
)
[3] => Array
(
[id] => 4
[name] => Item4
[parent] => 2
)
[4] => Array
(
[id] => 3
[name] => Item3
[parent] => 0
)
)
Demo on 3v4l.org
Update
It turns out that there is an inconsistency in the array structure; when there is only one child, only the child value is stored rather than a single element array. This can be dealt with by checking the the array to see if the id (Ид) element is set, and if it is, pushing the array one level deeper before processing:
function list_items($array, $parent = 0) {
$output = array();
if (isset($array['Ид'])) {
$array = array($array);
}
foreach ($array as $arr) {
if (!is_array($arr)) echo $arr;
$output[] = array('id' => $arr['Ид'], 'name' => $arr['Наименование'], 'parent' => $parent);
if (is_array($arr['Группы']['Группа'] ?? NULL)) {
$output = array_merge($output, list_items($arr['Группы']['Группа'], $arr['Ид']));
}
}
return $output;
}
$items = list_items($array);
print_r($items);
Demo on 3v4l.org

Group rows of a multidimensional array and form comma-separated values within each group

I want to combine arrays having same category id and question id.
Sample input:
$array = [
[
'category_id' => 1,
'question_id' => 1,
'option_id' => 2,
'title' => 'Do you wear glasses?',
'answer' => 'no'
],
[
'category_id' => 1,
'question_id' => 2,
'option_id' => 3,
'title' => 'Your hobbies ?',
'answer' => 'movies'
],
[
'category_id' => 1,
'question_id' => 4,
'option_id' => 8,
'title' => 'what is your status?',
'answer' => 'single'
],
[
'category_id' => 1,
'question_id' => 2,
'option_id' => 1,
'title' => 'Your hobbies ?',
'answer' => 'travel'
],
];
The 2nd and 4th arrays contain the same question (same category id and same question id), so I would like to have their answer values merged together as a comma-separated string.
Desired result:
Array(
[0] => Array
(
[category_id] => 1
[question_id] => 1
[option_id] => 2
[title] => Do you wear glasses?
[answer] => no
)
[1] => Array
(
[category_id] => 1
[question_id] => 2
[option_id] => 3
[title] => Your hobbies ?
[answer] => movies,travel
)
[2] => Array
(
[category_id] => 1
[question_id] => 4
[option_id] => 8
[title] => what is your status?
[answer] => single
)
)
It is okay that the option id and title are overwritten while grouping because I am not using the option id and the title values will be identical within each group.
maybe something like this could work, not sure if there's a better way to do it tho:
new_array=array();
foreach($source_array as $e){
$insert=1;
foreach($new_array as $n)
if(array_search($e['title'], $n)==false){
$n['answer'].=", ".$e['answer'];
$insert=0;
}
}
if($insert){
$new_array[]=$e;
}
}
For an example array
Array
(
[0] => Array
(
[category_id] => 1
[question_id] => 1
)
[1] => Array
(
[category_id] => 2
[question_id] => 2
)
[2] => Array
(
[category_id] => 1
[question_id] => 1
)
)
You could do something like this as an illustration
// Define the array to work on
$array = array( array( 'category_id' => 1, 'question_id'=> 1), array( 'category_id' => 2, 'question_id' => 2), array( 'category_id' => 1, 'question_id' => 1));
// Initialize the result array containing only unique question_id/category_id combinations
$unique_array = array();
foreach ($array as $key) {
if (!count($unique_array)) {
$unique_array[] = $key;
} else {
$unique = 1;
foreach ($unique_array as $check) {
if ( $check['category_id'] == $key['category_id'] && $check['question_id'] == $key['question_id'] ) {
$unique = 0;
}
}
if ( $unique ) {
$unique_array[] = $key;
}
}
}
print_r($unique_array);
The output of the last print_r would be
Array
(
[0] => Array
(
[category_id] => 1
[question_id] => 1
)
[1] => Array
(
[category_id] => 2
[question_id] => 2
)
)
The reason I ask if order matters, is that if it doesn't matter, you can sort your array first, and then only compare each one to its previous sibling:
$source=array(array("cat_id"=>1,"ques_id"=>1,"opt_id"=>2,"title"=>"cid:1, qid:1, oid:2","answer"=>"whatever"),array("cat_id"=>1,"ques_id"=>2,"opt_id"=>3,"title"=>"cid:1, qid:2, oid:3","answer"=>"whatever"),array("cat_id"=>1,"ques_id"=>4,"opt_id"=>8,"title"=>"cid:1, qid:4, oid:8","answer"=>"whatever"),array("cat_id"=>1,"ques_id"=>2,"opt_id"=>1,"title"=>"cid:1, qid:2, oid:1","answer"=>"whtvr"));
print_r($source); // just to debug
usort($source,function($a,$b){
if($a["cat_id"]<$b["cat_id"])
return -1;
elseif($a["cat_id"]>$b["cat_id"])
return 1;
elseif($a["ques_id"]<$b["ques_id"])
return -1;
elseif($a["ques_id"]>$b["ques_id"])
return 1;
elseif($a["opt_id"]<$b["opt_id"])
return -1;
elseif($a["opt_id"]>$b["opt_id"])
return 1;
else
return 0;
});
$source=array_reduce($source,function(&$a,$b){
if(empty($a))
{
$a=array($b);
}
else
{
$cache=array_pop($a);
if($cache["cat_id"]==$b["cat_id"] && $cache["ques_id"]==$b["ques_id"])
{
$cache["answer"].=", ".$b["answer"];
$a[]=$cache;
}
else
{
$a[]=$cache;
$a[]=$b;
}
}
return $a;
},array());
print_r($source);
Outputs:
// first print_r
Array
(
[0] => Array
(
[cat_id] => 1
[ques_id] => 1
[opt_id] => 2
[title] => cid:1, qid:1, oid:2
[answer] => whatever
)
[1] => Array
(
[cat_id] => 1
[ques_id] => 2
[opt_id] => 3
[title] => cid:1, qid:2, oid:3
[answer] => whatever
)
[2] => Array
(
[cat_id] => 1
[ques_id] => 4
[opt_id] => 8
[title] => cid:1, qid:4, oid:8
[answer] => whatever
)
[3] => Array
(
[cat_id] => 1
[ques_id] => 2
[opt_id] => 1
[title] => cid:1, qid:2, oid:1
[answer] => whtvr
)
)
// second print_r
Array
(
[0] => Array
(
[cat_id] => 1
[ques_id] => 1
[opt_id] => 2
[title] => cid:1, qid:1, oid:2
[answer] => whatever
)
[1] => Array
(
[cat_id] => 1
[ques_id] => 2
[opt_id] => 1
[title] => cid:1, qid:2, oid:1
[answer] => whtvr, whatever
)
[2] => Array
(
[cat_id] => 1
[ques_id] => 4
[opt_id] => 8
[title] => cid:1, qid:4, oid:8
[answer] => whatever
)
)
Please be noted that you stated in your comment that option_id is irrelevant, so I didn't replace it; you can replace that too inside the anonymous function inside array_reduce if you need to.
$data = array();
//$new is the array in which you have data originally
foreach($new as $arrayK => $arrayV){
if(!isset($data[$arrayV['category_id']][$arrayV['question_id']]))
$data[$arrayV['category_id']][$arrayV['question_id']] = $arrayV;
else{
$option = $data[$arrayV['category_id']][$arrayV['question_id']]['option_id'] . ',' . $arrayV['option_id'];
$data[$arrayV['category_id']][$arrayV['question_id']]['option_id'] = $option;
$answer = $data[$arrayV['category_id']][$arrayV['question_id']]['answer'] . ',' . $arrayV['answer'];
$data[$arrayV['category_id']][$arrayV['question_id']]['answer'] = $answer;
}
}
$data will have the required data in mentioned format
Both answer and option will be comma seperated
foreach($arr as $k=>$a)
{
$common[$k] = search($arr,'category_id',$a['category_id'],'question_id',$a['question_id']);
$answers = array_map(function($item) { return $item['answer']; }, $common[$k]);
$options = array_map(function($item) { return $item['option_id']; }, $common[$k]);
foreach($common[$k] as $temp)
{
$finalAns = $temp;
$finalAns['answer'] = implode(",",$answers);
$finalAns['option_id'] = implode(",",$options);
}
$final[] = $finalAns;
}
$final = array_map("unserialize", array_unique(array_map("serialize", $final)));
echo "<pre>";
print_r($final);
Put Below function in your common function file or in same file.
function search($array, $key, $value, $key1, $value1)
{
$results = array();
if (is_array($array))
{
if (isset($array[$key]) && $array[$key] == $value && isset($array[$key1]) && $array[$key1] == $value1)
{
$results[] = $array;
}
foreach ($array as $subarray)
$results = array_merge($results, search($subarray, $key, $value,$key1,$value1));
}
return $results;
}
Your output would be
Array
(
[0] => Array
(
[category_id] => 1
[question_id] => 1
[option_id] => 2
[title] => Do you wear glasses?
[answer] => no
)
[1] => Array
(
[category_id] => 1
[question_id] => 2
[option_id] => 3,1
[title] => Your hobbies ?
[answer] => movies,travel
)
[2] => Array
(
[category_id] => 1
[question_id] => 4
[option_id] => 8
[title] => what is your status?
[answer] => single
)
)
There is no reason for convoluted logic or multiple loops.
Each group needs to have a unique identifier. Although the asker states that question_id is enough, you can guarantee uniqueness by combining question_id and category_id as a delimited string. Use this "composite identifier" as the first-level key while pushing data into the result array.
When a composite key is re-encountered ), then do not both to save all data -- only append data to the desired element(s).
When finished iterating, re-index the result array to remove the temporary composite keys (if you wish).
Code: (Demo)
$result = [];
foreach ($array as $row) {
$compositeKey = $row['category_id'] . '_' . $row['question_id'];
if (!isset($result[$compositeKey])) {
$result[$compositeKey] = $row;
} else {
$result[$compositeKey]['answer'] .= ",{$row['answer']}";
}
}
var_export(
array_values(
$result
)
);
P.s. Typically, it is better to form subarrays instead of comma-delimited strings. Subarrays allows better access to individual values and flexibility in presentation. If you ever change your mind about how to present the values, you'd otherwise need to remove or replace the commas and print something else. Save the hassle, leave presentation to your (view) presentation loop and implode the subarray values exactly as you wish.

PHP Grouping Array by Index [duplicate]

This question already has answers here:
Transposing multidimensional arrays in PHP
(12 answers)
Closed 10 months ago.
I have a multidimensional array:
Array
(
[type] => Array
(
[0] => text
[1] => portfolio
[2] => slide
[3] => text
)
[grid] => Array
(
[0] => 3
[1] => 5
[2] => 3
[3] => 4
)
[title] => Array
(
[0] => title1
[3] => title2
)
[content] => Array
(
[0] => content1
[3] => content2
)
[item] => Array
(
[1] => 6
[2] => 7
)
[pagination] => Array
(
[1] => 8
)
[order] => Array
(
[1] => desc
[2] => asc
)
)
And want to group it by [type] key given in the array:
Array (
[0] => Array (
[type] => text
[grid] => 3
[title] => title1
[content] => content1
)
[1] => Array (
[type] => portfolio
[grid] => 5
[item] => 6
[pagination] => 1
[order] => desc
)
[2] => Array (
[type] => slide
[grid] => 3
[item] => 7
[order] => asc
)
[3] => Array (
[type] => text
[grid] => 4
[title] => title2
[content] => content2
)
Is there a way or PHP function to do array grouping like that?
This snippet achieves that:
$result = array();
foreach ($array as $key => $data) {
foreach ($data as $offset => $value) {
if (isset($result[$offset])) {
$result[$offset][$key] = $value;
} else {
$result[$offset] = array($key => $value);
}
}
}
Working DEMO
array_map() with null for the callback will do exactly what you want. However it will have number for the index instead of names.
If you write your own callback then you can return an array with the names you need.
Since apparently people want the actual code:
array_map(null, $type_array, $grid_array, $title_array, $content_array, $item_array);
It really is as simple as that. Most of the other answers are so large and unnecessary.
Note: This assumes a fixed number of arrays - if it's not fixed then this won't work, and then go with Florent's answer.
You can do it with this function:
$type_array = array('text', 'portfolio', 'slide', 'text');
$grid_array = array(3, 5, 3, 4);
$title_array = array(0 => 'title1', 3 => 'title2');
$content_array = array(0 => 'content1', 3 => 'content2');
$item_array = array(1 => 6, 2 => 7);
function group_arrays($type_array, $grid_array, $title_array, $content_array, $item_array) {
$temp_array = array();
for($i = 0; $i < count($type_array); $i++) {
$temp_array[$i] = array( 'type' => #$type_array[$i],
'grid' => #$grid_array[$i],
'title' => #$title_array[$i],
'content' => #$content_array[$i],
'item' => #$item_array[$i]);
}
return $temp_array;
}
print_r(group_arrays($type_array, $grid_array, $title_array, $content_array, $item_array));
Hope this helps!

PHP Reorder array to reflect parent / id hierarchy

How do I rearrange the following array
[0] => Array
(
[id] => 1
[parent_id] => 0
[name] => Accueil
)
[1] => Array
(
[id] => 2
[parent_id] => 0
[name] => Exposants
)
[2] => Array
(
[id] => 3
[parent_id] => 0
[name] => Visiteurs
)
[3] => Array
(
[id] => 4
[parent_id] => 0
[name] => Medias
)
[4] => Array
(
[id] => 5
[parent_id] => 0
[name] => Activités
)
[5] => Array
(
[id] => 6
[parent_id] => 1
[name] => Contact
)
[6] => Array
(
[id] => 7
[parent_id] => 3
[name] => Partenaires
)
[7] => Array
(
[id] => 8
[parent_id] => 2
[name] => News
)
So I come up with an array that reflects the hierarchy as shown by the id and parent_id fields? The array key is the ID field of array elements are parents. Inside this array is each time a child array that has its ID field as the key. Sample:
[1] => Array
(
[name] => Accueil
[children] => array(
[0] => bla,
[3] => bla2
)
)
[2] => Array
(
[name] => Something
[children] => array(
[4] => bla3,
)
)
Works for any depth and allows children to precede parents:
<?php
$p = array(0 => array());
foreach($nodes as $n)
{
$pid = $n['parent_id'];
$id = $n['id'];
if (!isset($p[$pid]))
$p[$pid] = array('child' => array());
if (isset($p[$id]))
$child = &$p[$id]['child'];
else
$child = array();
$p[$id] = $n;
$p[$id]['child'] = &$child;
unset($p[$id]['parent_id']);
unset($child);
$p[$pid]['child'][] = &$p[$id];
}
$nodes = $p['0']['child'];
unset($p);
?>
Use var_dump on the $nodes result to see the structure. It is close to what you suggested. The major difference is that the keys are not the ids.
You could make this more DRY, but it's a quick and dirty way to handle it. Also, you could remove 6 lines if you could guarantee that each child record has a valid parent record and that the valid parent record precedes the child record in the original array.
$sorted = array();
foreach( $orig_ary as $item ) {
if ( $item['parent_id'] === 0 ) {
if ( !array_key_exists( $item['id'], $sorted ) ) {
$sorted[ $item['id'] ] = array(
'name' => '',
'children' => array()
);
}
$sorted[ $item['id'] ]['name'] = $item['name'];
} else {
if ( !array_key_exists( $item['parent_id'], $sorted ) ) {
$sorted[ $item['parent_id'] ] = array(
'name' => '',
'children' => array()
);
}
$sorted[ $item['parent_id'] ]['children'][ $item['id'] ] = $item['name'];
}
}

Categories