Tree(or hierarchy) array to two dimensional structured array in php - php

How can I convert a tree like array to two dimensional linear array? Still now I am stuck into this question. May be somebody ask this question but yet now I didn't get a proper way.
$str='[{"id":1},{"id":2,"children":[{"id":3,"children":[{"id":4}]},{"id":5,"children":[{"id":6},{"id":7,"children":[{"id":8}]}]},{"id":9},{"id":10}]},{"id":11,"children":[{"id":12}]}]'
This is my json string when I convert it to array using json_decode() function. I got the following result
Array
(
[0] => stdClass Object
(
[id] => 1
)
[1] => stdClass Object
(
[id] => 2
[children] => Array
(
[0] => stdClass Object
(
[id] => 3
[children] => Array
(
[0] => stdClass Object
(
[id] => 4
)
)
)
[1] => stdClass Object
(
[id] => 5
[children] => Array
(
[0] => stdClass Object
(
[id] => 6
)
)
)
[2] => stdClass Object
(
[id] => 7
)
[3] => stdClass Object
(
[id] => 8
)
)
)
[2] => stdClass Object
(
[id] => 9
[children] => Array
(
[0] => stdClass Object
(
[id] => 10
)
)
)
)
This is like a tree structure but I need to convert it into a two dimensional array like
Array
(
[0] => Array
(
[parent] => 0
[id] => 1
)
[1] => Array
(
[parent] => 0
[id] => 2
)
[2] => Array
(
[parent] => 2
[id] => 3
)
[3] => Array
(
[parent] => 3
[id] => 4
)
[4] => Array
(
[parent] => 2
[id] => 5
)
[5] => Array
(
[parent] => 5
[id] => 6
)
[6] => Array
(
[parent] => 2
[id] => 7
)
[7] => Array
(
[parent] => 2
[id] => 8
)
[8] => Array
(
[parent] => 0
[id] => 9
)
[9] => Array
(
[parent] => 0
[id] => 10
)
)

You'll need to write a recursive function and/or a loop to sort your object into an array like the one you specified.
I'll start by saying that in future if you could post sample data and expected output that actually matches what you want and expect that would be great - because I just spent ten minutes working out why my function is telling me that the parent of id 7 is id 5 when your example says it should be 2, when your JSON and your example array are actually different - annoying.
Anyway, here's the idea:
Recursive function to check for children in the passed array. If they exist, call the function again on its children. Add the current to the output array regardless of whether there are children or not.
&$output = output variable passed by reference, so you don't need to return anything and can access the output variable without a global call.
$parent_id represents the parent id each time you're iterating over children. In the first cases where the node doesn't have a parent, the declaration $parent_id = 0 will define your "default" parent ID. Otherwise, the parent ID is passed each time you go deeper.
function checkForChildrenOtherwiseAddToArray(&$output, $array, $parent_id = 0) {
// loop through all sub-arrays inside this instance (if any)
foreach($array as $each) {
// check for children
if(isset($each->children)) {
// go deeper, passing in children and parent ID
checkForChildrenOtherwiseAddToArray($output, $each->children, $each->id);
}
// add current iteration to array as well
$output[] = array(
'parent' => $parent_id,
'id' => $each->id
);
}
}
Example use:
$your_array = json_decode($str);
$output = array();
checkForChildrenOtherwiseAddToArray($output, $your_array);
This will give you results that are seemingly un-ordered because of the recursive nature of this function. To sort by id for example you could use usort():
usort($output, function($a, $b) {
return $a['id'] - $b['id'];
});
... and your example output would be:
Array
(
[0] => Array
(
[parent] => 0
[id] => 1
)
[1] => Array
(
[parent] => 0
[id] => 2
)
[2] => Array
(
[parent] => 2
[id] => 3
)
[3] => Array
(
[parent] => 3
[id] => 4
)
[4] => Array
(
[parent] => 2
[id] => 5
)
[5] => Array
(
[parent] => 5
[id] => 6
)
[6] => Array
(
[parent] => 5
[id] => 7
)
[7] => Array
(
[parent] => 7
[id] => 8
)
[8] => Array
(
[parent] => 2
[id] => 9
)
[9] => Array
(
[parent] => 2
[id] => 10
)
[10] => Array
(
[parent] => 0
[id] => 11
)
[11] => Array
(
[parent] => 11
[id] => 12
)
)

Related

Flatten Array php

I'm trying to flat a multidimensional array to a given specific format.
I have a tree that is saved as a nested array, which is ok, but the function given to render the array in the UI expects only one array and, per each child, an independent array. Instead of the nested array, each option should be at the same level.
This is how my var_dump of my array:
(
[id] => 1
[name] => some data.
[emoji] => 🐕
[parent_id] =>
[children] => Array
(
[0] => Array
(
[id] => 2
[name] => Food
[emoji] => 🥩
[parent_id] => 1
[children] => Array
(
)
)
[1] => Array
(
[id] => 3
[name] => some other data
[emoji] => 😌
[parent_id] => 1
[children] => Array
(
[0] => Array
(
[id] => 4
[name] => Massages
[emoji] => 💆
[parent_id] => 3
[children] => Array
(
)
)
[1] => Array
(
[id] => 5
[name] => Games
[emoji] => 🎾
[parent_id] => 3
[children] => Array
(
)
)
)
)
)
)
)
And the expected result should be:
0] => Array
(
[id] => 1
[name] => Rusty Corp.
[emoji] => 🐕
[parent_id] =>
)
[1] => Array
(
[id] => 2
[name] => Food
[emoji] => 🥩
[parent_id] => 1
)
[2] => Array
(
[id] => 3
[name] => Canine Therapy
[emoji] => 😌
[parent_id] => 1
)
[3] => Array
(
[id] => 4
[name] => Massages
[emoji] => 💆
[parent_id] => 3
)
[4] => Array
(
[id] => 5
[name] => Games
[emoji] => 🎾
[parent_id] => 3
)
I tried different approaches like array_merge or custom flattening function but can't nail with the expected results, any suggestions?
Edit:
This is my flatten function:
private function flatten_array( array $array ) {
$return = array();
array_walk_recursive(
$array,
function( $a ) use ( &$return ) {
$return[] = $a;
}
);
return $return;
}
Here is a recursive function that will flatten the array, it will not take into account the null value of parent_id on the root element. Also the flattened array will start with the most nested elements at the start of the array and root element at the end.
function flatten_array($array, $flattened = []) {
$current = [];
foreach ($array as $key => $value) {
if (is_array($value))
$flattened = array_merge($flattened, flatten_array($value));
else
$current[$key] = $value;
}
$flattened[] = $current;
return array_filter($flattened);
}

Shift Recursive nested child array to parent array PHP

I have an issue with forming a recursive array. That is shifting the child array nodes to direct elements to a parent array.
like from,
Array
(
[0] => Array
(
[id] => 1
[category_name] => flare
[parent_category_id] => 0
[childrenrecursive] => Array
(
[0] => Array
(
[id] => 2
[category_name] => analytics
[parent_category_id] => 1
[braincount] => Array
(
[count] => 3
[category_id] => 2
)
[childrenrecursive] => Array
(
[0] => Array
(
[id] => 4
[category_name] => sports analytics
[parent_category_id] => 2
[braincount] => Array
(
[count] => 4
[category_id] => 4
)
[childrenrecursive] => Array
(
)
)
)
)
[1] => Array
(
[id] => 3
[category_name] => cluster
[parent_category_id] => 1
[braincount] => Array
(
[count] => 4
[category_id] => 3
)
[childrenrecursive] => Array
(
)
)
)
)
)
to,
Array
(
[0] => Array
(
[id] => 1
[category_name] => flare
[parent_category_id] => 0
[childrenrecursive] => Array
(
[0] => Array
(
[id] => 2
[category_name] => analytics
[parent_category_id] => 1
[count] => 3
[category_id] => 2
[childrenrecursive] => Array
(
[0] => Array
(
[id] => 4
[category_name] => sports analytics
[parent_category_id] => 2
[count] => 4
[category_id] => 4
[childrenrecursive] => Array
(
)
)
)
)
[1] => Array
(
[id] => 3
[category_name] => cluster
[parent_category_id] => 1
[count] => 4
[category_id] => 3
[childrenrecursive] => Array
(
)
)
)
)
)
only by moving following child array append to parent in a recursive way.
[braincount] => Array
(
[count] => 4
[category_id] => 3
)
can anybody help me to format the array like specified.
Let's say $input is the array posted in the question:
/**
* If $value is an array then move the content of 'braincount' one level up
* (in $value) then call recursively for all its children.
*/
function moveUp($value)
{
// Not an array? Nothing to do; return the input value unchanged
if (! is_array($value)) {
return $value;
}
// Move the content of 'braincount' (if present) one level up
if (array_key_exists('braincount', $value)) {
$value = array_merge($value, $value['braincount']);
unset($value['braincount']);
}
// Apply the same operation to all children
return array_map(__FUNCTION__, $value);
}
// Verify it works
print_r(moveUp($input));

merge two multidimensional array based on same ID

I am facing one issue when merging two multidimensional arrays based on the same ID.
In the example below I created two arrays - Array1 and Array2. Both arrays contain objects that have an ID property. Based on the ID property, the arrays should be merged and get the result array:
Array1
Array
(
[0] => stdClass Object
(
[claimtotal] =>
[total] => 4
[ID] => 3
)
[1] => stdClass Object
(
[claimtotal] => 20
[total] => 1
[ID] => 4
)
)
Array2
Array
(
[0] => stdClass Object
(
[ID] =>2
[name] => test1
)
[1] => stdClass Object
(
[ID] => 3
[name] => test2
)
[2] => stdClass Object
(
[ID] =>4
[name] => test3
)
[3] => stdClass Object
(
[ID] => 5
[name] => test4
)
)
Result_array
Array
(
[0] => stdClass Object
(
[ID] =>2
[name] => test1
[claimtotal] =>
[total] =>
)
[1] => stdClass Object
(
[ID] => 3
[name] => test2
[claimtotal] =>
[total] => 4
)
[2] => stdClass Object
(
[ID] =>4
[name] => test3
[claimtotal] => 20
[total] => 1
)
[3] => stdClass Object
(
[ID] => 5
[name] => test4
[claimtotal] =>
[total] =>
)
)
How can I achieve this?
if these are simple objects without methods go:
foreach($firstArray as $key => $firstObject){
foreach($secondArray as $secondObject){
if($firstObject['id'] === $secondObject['id']){
$firstArray[$key] = (object) array_merge((array) $firstObject, (array) $secondObject);
}
}
}
looks messy but does the job without introducing another loop to go through object properties.

PHP add arrays to an array on a specific element

I am trying to merge 2 arrays a single array on a multidimensional array where a given key-value = a value
the first array looks like this:
Array
(
[0] => Array
(
[id] => 4
[subcategories] => Array
(
[0] => Array
(
[id] => 5
[category_order] => 0
[parent_id] => 4
[name] => Audio Equipment
)
[1] => Array
(
[id] => 6
[category_order] => 0
[parent_id] => 4
[name] => Home Entertainment
)
[2] => Array
(
[id] => 7
[category_order] => 0
[parent_id] => 4
[name] => Photography
)
[3] => Array
(
[id] => 8
[category_order] => 0
[parent_id] => 4
[name] => Portable Audio
)
[4] => Array
(
[id] => 9
[category_order] => 0
[parent_id] => 4
[name] => Televisions
)
)
)
)
and the second like this:
Array
(
[0] => Array
(
[id] => 10
[parent_id] => 5
[name] => Amplifiers & Receivers
)
[1] => Array
(
[id] => 11
[parent_id] => 5
[name] => Audio Systems
)
[2] => Array
(
[id] => 12
[parent_id] => 5
[name] => Cassette Decks
)
[3] => Array
(
[id] => 13
[parent_id] => 5
[name] => CD Players
)
[4] => Array
(
[id] => 14
[parent_id] => 5
[name] => Radios
)
[5] => Array
(
[id] => 15
[parent_id] => 5
[name] => HiFi Speakers
)
)
What I want to do is add each of the second arrays to a sub array of the first multidimensional array where the parent_id of the second array = the id of the subcategories array of the first array so it will look like this:
array
(
[0]=> Array
(
[id] => 4
[subcategories] => Array
(
[0] => Array
(
[id] => 5
[category_order] => 0
[parent_id] => 4
[name] => Audio Equipment
[subsubcategories] = array
(
[id] => 10
[parent_id] => 5
[name] => Amplifiers & Receivers
)
)
Something like this should work just rename the array names because you didn't provide them. But I think you'll get the idea :) Mainly you loop through all subcategories with foreach loop or another you'll get the parent id and can access the main array with that parent id and save the sub categories info in there.
foreach( $sub_array as $item ) {
$main_array[ category_id ][ $item[ 'parent_id' ] ][ 'subsubcategories' ] = $item;
}

Sort stdClass Object after an array

I have two arrays,
Array
(
[0] => stdClass Object
(
[id] => 1
[title] => art
)
[1] => stdClass Object
(
[id] => 4
[title] => adsdf
)
[2] => stdClass Object
(
[id] => 2
[title] => adsdf
)
[3] => stdClass Object
(
[id] => 7
[title] => adsdf
)
)
Array
(
[2] => 2
[1] => 1
)
And I want to sort the first array after the second array. In the second array the key and the value is equal with the first array id. So the output have to be the following.
Array
(
[0] => stdClass Object
(
[id] => 2
[title] => adsdf
)
[1] => stdClass Object
(
[id] => 1
[title] => art
)
[2] => stdClass Object
(
[id] => 4
[title] => adsdf
)
[3] => stdClass Object
(
[id] => 7
[title] => adsdf
)
)
You can use array_multisort[Docs] for it:
array_multisort($arraySort, $arrayData);
Pass the array with the sort order as the first and your array to be sorted as the second parameter.
You might need to build the sort array prior to it, from your question it's not clear to me if you already have it or not.
In case not, if you want to get all of the data arrays entries ID values into the sort array:
$arraySort = array();
foreach($arrayData as $key => $obj)
{
$arraySort[$key] = $obj->id;
}

Categories