Merge array by element's parent_id in PHP - php

I am not sure if this has already been asked in PHP but I couldn't find the answer
I have an array that lists id and parent id
$cats = [▼
0 => array:4 [▼
"id" => 5
"parent_id" => 4
"category" => "Detroit"
"children" => []
]
1 => array:4 [▼
"id" => 4
"parent_id" => 3
"category" => "Michigan"
"children" => []
]
2 => array:4 [▼
"id" => 2
"parent_id" => 1
"category" => "Cannes"
"children" => []
]
3 => array:4 [▼
"id" => 1
"parent_id" => 0
"category" => "France"
"children" => []
]
4 => array:4 [▼
"id" => 3
"parent_id" => 0
"category" => "United States"
"children" => []
]
]
I want to loop by parent id backwards to merge the grandchildren into the children and the children into the parent.
I tried to find the parent by id using array search and then push the child into the parent's children array
foreach ($cats as $element){
//If not the root level
if($element['parent_id']!==0){
//Find parent index
$parent_index = array_search($element['parent_id'],array_column($cats,'id'));
//Push Child
array_push($cats[$parent_index]['children'],$element);
}
}
I figure I need to unset the original child after it is pushed into the parent array but it seems when the child is pushed into the parent, the grandchild is missing (as you can see by the last entry of United States [index 4] having Michigan but not Detroit) which I though would have been updated in index 2.
array:5 [▼
0 => array:4 [▼
"id" => 5
"parent_id" => 4
"category" => "Detroit"
"children" => []
]
1 => array:4 [▼
"id" => 4
"parent_id" => 3
"category" => "Michigan"
"children" => array:1 [▼
0 => array:4 [▼
"id" => 5
"parent_id" => 4
"category" => "Detroit"
"children" => []
]
]
]
2 => array:4 [▼
"id" => 2
"parent_id" => 1
"category" => "Cannes"
"children" => []
]
3 => array:4 [▼
"id" => 1
"parent_id" => 0
"category" => "France"
"children" => array:1 [▼
0 => array:4 [▼
"id" => 2
"parent_id" => 1
"category" => "Cannes"
"children" => []
]
]
]
4 => array:4 [▼
"id" => 3
"parent_id" => 0
"category" => "United States"
"children" => array:1 [▼
0 => array:4 [▼
"id" => 4
"parent_id" => 3
"category" => "Michigan"
"children" => []
]
]
]
]
I appreciate any hint or answers on what I am doing wrong or why this isn't working. Thanks!

Every time I see an arbitrarily nested array I think of recursion. You cannot do this with only one loop through the array.
This is my approach: loop through the array looking for children and append them to a new array, the first time to an empty array, successive times to the children array, recursively.
$cats = [
[
"id" => 5,
"parent_id" => 4,
"category" => "Detroit",
"children" => [],
],
[
"id" => 4,
"parent_id" => 3,
"category" => "Michigan",
"children" => [],
],
[
"id" => 2,
"parent_id" => 1,
"category" => "Cannes",
"children" => [],
],
[
"id" => 1,
"parent_id" => 0,
"category" => "France",
"children" => [],
],
[
"id" => 3,
"parent_id" => 0,
"category" => "United States",
"children" => [],
]
];
$out = [];
function get_children($in, &$out, $parent){
foreach ($in as $item) {
if ($parent == $item["parent_id"]){
$out[] = $item;
get_children($in, $out[count($out)-1]["children"], $item["id"]);
}
}
}
get_children($cats, $out, 0);
print_r($out);
//OUTPUT:
Array
(
[0] => Array
(
[id] => 1
[parent_id] => 0
[category] => France
[children] => Array
(
[0] => Array
(
[id] => 2
[parent_id] => 1
[category] => Cannes
[children] => Array
(
)
)
)
)
[1] => Array
(
[id] => 3
[parent_id] => 0
[category] => United States
[children] => Array
(
[0] => Array
(
[id] => 4
[parent_id] => 3
[category] => Michigan
[children] => Array
(
[0] => Array
(
[id] => 5
[parent_id] => 4
[category] => Detroit
[children] => Array
(
)
)
)
)
)
)
)
It might not be the most performant solution and I'm not knowledgeable enough to tell you the time or space complexity, but hey, it works!
EDIT
I realized only later that you can delete the elements from the original array when you add them to the new array, this should make it much more performant:
function get_children(&$in, &$out, $parent){
foreach ($in as $key=>$item) {
if ($parent == $item["parent_id"]){
$out[] = $item;
unset($in[$key]);
get_children($in, $out[count($out)-1]["children"], $item["id"]);
}
}
}

Related

php create an assoc array with customer_id

I want to create and php associative array from an array like bellow
array:3 [▼
0 => array:7 [▼
"item_id" => "1"
"customer_id" => "53453"
"name" => "Item3"
"price" => 0
"quantity" => 1
]
1 => array:7 [▼
"item_id" => "3"
"customer_id" => "53453"
"name" => "Item1"
"price" => 0
"quantity" => 1
]
2 => array:7 [▼
"item_id" => "2"
"customer_id" => "765656"
"name" => "Item2"
"price" => 0
"quantity" => 1
]
]
I want to create an assoc with customer_id from this array like bellow. My goal is to create an assoc array with common customer_id for get all customer itmes.
array:2 [▼
// if common customer id, make an item array for the customer
53453=> array:2 [▼
0 => array:3 [▼
"quantity" => "1"
"name" => "Item1"
"price" => 0
],
1 => array:3 [▼
"quantity" => "1"
"name" => "Item3"
"price" => 0
]
]
78640 => array:1 [▼
0 => array:3 [▼
"quantity" => "1"
"name" => "Item2"
"price" => 0
]
]
]
You can group by customer_id using the same key, and and the old array without the keys you don't want.
$array = [
["item_id" => "1", "customer_id" => "53453", "name" => "Item3", "price" => 0, "quantity" => 1],
["item_id" => "3", "customer_id" => "53453", "name" => "Item1", "price" => 0, "quantity" => 1],
["item_id" => "2", "customer_id" => "765656", "name" => "Item2", "price" => 0, "quantity" => 1],
];
$finalArray = [];
foreach ($array as $item)
{
$customer_id = $item['customer_id'];
unset($item['customer_id']);
unset($item['item_id']);
$finalArray[$customer_id][] = $item;
}
print_r($finalArray);
Outputs :
Array
(
[53453] => Array
(
[0] => Array
(
[name] => Item3
[price] => 0
[quantity] => 1
)
[1] => Array
(
[name] => Item1
[price] => 0
[quantity] => 1
)
)
[765656] => Array
(
[0] => Array
(
[name] => Item2
[price] => 0
[quantity] => 1
)
)
)
online example
Or if you only want the create some selected keys :
$finalArray[$customer_id][] = [
'name' => $item['name'],
'price' => $item['price'],
'quantity' => $item['quantity'],
];
online example
$newarray=[];
foreach ($firstarray as $fa)
{
$tarray=array($fa['qty'],$fa['name'],$fa['price']);
$newarray[$fa['customer_id']][]=$tarray;
}
... and the result you want will be in $newarray, more or less.

PHP combine multi-dimensional arrays

I'm have the following array.
"rent" => array:3 [
0 => array:1 [
0 => "5000"
]
1 => array:3 [
0 => "10000"
1 => "60000"
2 => "80000"
]
2 => []
]
"house_quantity" => array:3 [
0 => array:1 [
0 => "2"
]
1 => array:3 [
0 => "3"
1 => "4"
2 => "6"
]
2 => []
]
"property_id" => array:3 [
0 => 1
1 => 2
2 => 3
]
"type_of_house" => array:3 [
0 => array:1 [
0 => array:1 [
"type" => "studio_apartment"
]
]
1 => array:3 [
0 => array:1 [
"type" => "studio_apartment"
]
1 => array:1 [
"type" => "one_bedroom"
]
2 => array:1 [
"type" => "two_bedroom"
]
]
2 => array:2 [
0 => array:1 [
"type" => "studio_apartment"
]
1 => array:1 [
"type" => "two_bedroom"
]
]
]
]
I want to combine the above array so that it forms an array that looks like this.
"0" => [
"property_id" => 1
"type_of_house" => array:3 [
"type"=> "studio_apartment"
"rent" => "5000"
"house_quantity" => "2"
]
]
"1" => [
"property_id" => 2
"type_of_house" => array:3 [
"type"=> "studio_apartment"
"rent" => "10000"
"house_quantity" => "3"
]
"type_of_house" => array:3 [
"type"=> "one_bedroom"
"rent" => "60000"
"house_quantity" => "4"
]
"type_of_house" => array:3 [
"type"=> "two_bedroom"
"rent" => "80000"
"house_quantity" => "6"
]
]
So far I'm using the foreach loop to loop over the properties and attach the type of houses in each of those properties as follows:
foreach ($request->property_id as $key=> $property_id) {
$result[$key] = array(
'property_id' => $property_id,
'type_of_house' => $request->type_of_house[$key]
);
foreach ($result as $property_key => $property) {
foreach ($property['type_of_house'] as $house_key => $house) {
$house[$key][$house_key] = array(
'rent' => $request->rent[$key][$house_key],
'house_quantity' => $request->house_quantity[$key][$house_key]
);
}
}
$merge = array_merge_recursive($result, $house);
dd($merge);
}
But the array I'm getting back is not quite right. This is the array that I'm getting back.
array:3 [
0 => array:2 [
"property_id" => 1
"type_of_house" => array:1 [
0 => array:1 [
"type" => "studio_apartment"
]
]
]
"type" => "studio_apartment"
1 => array:1 [
0 => array:2 [
"rent" => "5000"
"house_quantity" => "2"
]
]
]
How do I correctly merge such an array, thanks.
Ok, so let's suppose you have 2 arrays
$array1:
Array(2){
[number] => 1,
[address] => "Park Ave 273",
[name] => "Peter Jones"
}
And then a clean $array2, the one i'm gonna be putting my info
To mix them i would have to specify the index i want the first array to get in, for example:
$array1 = array(
"number" => 1,
"address" => "Park Ave 273",
"name" => "Peter Jones"
);
$array2 = array();
$array2['client'] = $array1;
Would return:
Array
(
[client] => Array
(
[number] => 1
[address] => Park Ave 273
[name] => Peter Jones
)
)
In case you have more than one client (on this example) you have to do a foreach loop for every client.

Merging one array into another

I have 2 arrays
Array 1:
array:3 [▼
0 => 1
1 => 2.3
2 => 4.5
]
Array 2:
array:3 [▼
0 => array:2 [▼
"name" => "john"
"age" => 34
]
1 => array:2 [▼
"name" => "doe"
"age" => 12
]
2 => array:2 [▼
"name" => "kelvin"
"age" => 14
]
]
How do I merge array 1 into array 2 so that I have something like this-
array:3 [▼
0 => array:3 [▼
"name" => "john"
"age" => 34,
"score" => 1
]
1 => array:3 [▼
"name" => "doe"
"age" => 12,
"score" => 2.3
]
2 => array:3 [▼
"name" => "kelvin"
"age" => 14,
"score" => 4.5
]
]
Notice that the values of array 1 now have keys called 'score'.
You can use foreach loop with reference &:
$ar = [1,2,3.4];
$ar2 = [['name'=>'Joe','age' => 33],['name'=>'Joe2','age' => 33],['name'=>'Joe3','age' => 33]];
foreach($ar2 as $ind=>&$person){
$person['score'] = $ar[$ind];
}
print_r($ar2);
Demo
Output:
Array
(
[0] => Array
(
[name] => Joe
[age] => 33
[score] => 1
)
[1] => Array
(
[name] => Joe2
[age] => 33
[score] => 2
)
[2] => Array
(
[name] => Joe3
[age] => 33
[score] => 3.4
)
)
You can also use array_walk to walk through the array.
<?php
$a = [1,2.3,4.5];
$b = [
["name" => "john", "age" => 34],
["name" => "doe","age" => 12],
["name" => "kelvin", "age" => 14]
];
array_walk($a,function($val,$key) use (&$b){
$b[$key]['score'] = $val;
});
print_r($b);
Demo: https://3v4l.org/58rXG

how to get first key (0 or associative ) form array and output in new array

I Would Like To Get The First Element Of This Array And Put In New Same Array Output
One Requirement: It Cannot Be Done With Passing By reference Index eg 0
This Input Array
[ 'id','ID','dt-text' ] ,
[ 'name','Name','dt-text' ] ,
[ 'artistList'=>['list','mm','defalut'] ,'Artist List','dt-select'] ,
[ 'nationality'=>['nationality','mm','defalut'] ,'Nationality','dt-select'] ,
[ 'view','View',''],
[ 'status','Status' ,'']
array:6 [▼
0 => array:3 [▼
0 => "id"
1 => "ID"
2 => "dt-text"
]
1 => array:3 [▼
0 => "name"
1 => "Name"
2 => "dt-text"
]
2 => array:3 [▼
"artistList" => array:3 [▼
0 => "list"
1 => "mm"
2 => "defalut"
]
0 => "Artist List"
1 => "dt-select"
]
3 => array:3 [▼
"nationality" => array:3 [▼
0 => "nationality"
1 => "mm"
2 => "defalut"
]
0 => "Nationality"
1 => "dt-select"
]
4 => array:3 [▼
0 => "view"
1 => "View"
2 => ""
]
5 => array:3 [▼
0 => "status"
1 => "Status"
2 => ""
]
]
The New Array I Needed
This IS OutPUT Array
['id','name','artistList'=>['list','mm','defalut'] ,'nationality'=>['nationality','mm','defalut'] ,'view','status']
array:6 [▼
0 => "id"
1 => "name"
"artistList" => array:3 [▼
0 => "list"
1 => "mm"
2 => "defalut"
]
"nationality" => array:3 [▼
0 => "nationality"
1 => "mm"
2 => "defalut"
]
2 => "view"
3 => "status"
]
Note
I Can Controll in Input Array Same , I Try with foreach in php And Tray In Laravel Helper Function head Put I get S
array:6 [▼
0 => "id"
1 => "name"
2 => array:1 [▼
"artistList" => array:3 [▼
0 => "list"
1 => "mm"
2 => "defalut"
]
]
3 => array:1 [▼
"nationality" => array:3 [▼
0 => "nationality"
1 => "mm"
2 => "defalut"
]
]
4 => "view"
5 => "status"
]
Put I Cant Get Resslut So , How Can I Do this?
Since you are changing the keys (structure) of the array, there is no way to do that without either generating a new array or passing the array by reference. One way to do it by generating a new array is with array_reduce:
$array = [
[ 'id','ID','dt-text' ] ,
[ 'name','Name','dt-text' ] ,
[ 'artistList'=>['list','mm','defalut'] ,'Artist List','dt-select'] ,
[ 'nationality'=>['nationality','mm','defalut'] ,'Nationality','dt-select'] ,
[ 'view','View',''],
[ 'status','Status' ,'']
];
$array = array_reduce($array, function ($c, $v) {
$first_key = array_keys($v)[0];
return array_merge($c, array($first_key => $v[$first_key])); }, []);
print_r($array);
Output:
Array (
[0] => id
[1] => name
[artistList] => Array (
[0] => list
[1] => mm
[2] => defalut
)
[nationality] => Array (
[0] => nationality
[1] => mm
[2] => defalut
)
[2] => view
[3] => status
)
Demo on 3v4l.org

Cross compare two array elements

After a lot of API calls and loops I have created an array. This array takes the following form
2 => array:3 [▼
"someInfo" => array:1 [▶]
"existingIDs" => array:1 [▼
0 => array:1 [▼
"id" => "123456"
]
]
"idList" => array:2 [▼
0 => array:1 [▼
"id" => "123456"
]
1 => array:1 [▼
"id" => "777564"
]
]
]
The part I am interested in is existingIDs and idList. The problem is that some ids are appearing in both array elements, so in the above example the id 123456 appears in both.
What I need to do is cross compare these two elements and perhaps create a new element with unique ids. So the above example may turn into something like this
2 => array:3 [▼
"someInfo" => array:1 [▶]
"existingIDs" => array:1 [▼
0 => array:1 [▼
"id" => "123456"
]
]
"idList" => array:2 [▼
0 => array:1 [▼
"id" => "123456"
]
1 => array:1 [▼
"id" => "777564"
]
]
"uniqueList" => array:2 [
0 => array:1 [
"id" => "123456"
]
1 => array:1 [
"id" => "777564"
]
]
]
How could something like this be achieved?
Thanks
Use the following approach with array_column(available since PHP 5.5), array_merge and array_unique functions:
$arr = [
"someInfo" => [],
"existingIDs" => [
["id" => "123456"]
],
"idList" => [
["id" => "123456"],
["id" => "777564"],
["id" => "777564"]
]
];
$all_ids = array_merge(array_column($arr['existingIDs'], 'id'), array_column($arr['idList'], 'id'));
$arr['uniqueList'] = array_unique($all_ids);
print_r($arr);
The output:
Array
(
[someInfo] => Array
(
)
[existingIDs] => Array
(
[0] => Array
(
[id] => 123456
)
)
[idList] => Array
(
[0] => Array
(
[id] => 123456
)
[1] => Array
(
[id] => 777564
)
[2] => Array
(
[id] => 777564
)
)
[uniqueList] => Array
(
[0] => 123456
[2] => 777564
)
)

Categories