I have an array of arrays - each has own id and parent id values. I want to sort it so that every child should be beneath its parent.
Given Array:
$arr = array(
array('id' => 15, 'parent' => 12),
array('id' => 10, 'parent' => 12),
array('id' => 12, 'parent' => 12),
array('id' => 17, 'parent' => 12),
array('id' => 21, 'parent' => 15),
array('id' => 13, 'parent' => 15),
array('id' => 15, 'parent' => 15),
array('id' => 25, 'parent' => 15),
array('id' => 7, 'parent' => 7),
array('id' => 18, 'parent' => 7),
array('id' => 4, 'parent' => 7),
array('id' => 1, 'parent' => 3),
array('id' => 5, 'parent' => 5),
array('id' => 2, 'parent' => 7)
);
How the output should look like (asc by parents, every children also ascending - always under parent (parent always as first!!!)):
0 =>
'id' => int 1
'parent' => int 3
1 =>
'id' => int 5
'parent' => int 5
2 =>
'id' => int 7
'parent' => int 7
3 =>
'id' => int 2
'parent' => int 7
4 =>
'id' => int 4
'parent' => int 7
5 =>
'id' => int 18
'parent' => int 7
6 =>
'id' => int 12
'parent' => int 12
7 =>
'id' => int 10
'parent' => int 12
8 =>
'id' => int 15
'parent' => int 12
9 =>
'id' => int 17
'parent' => int 12
10 =>
'id' => int 15
'parent' => int 15
11 =>
'id' => int 13
'parent' => int 15
12 =>
'id' => int 21
'parent' => int 15
13 =>
'id' => int 25
'parent' => int 15
I'm wondering what is the easiest solution to achieve this. I've managed to do that, but I can't stop the feeling that there is a way to do that in quicker and more optimal way.
Here is my code:
function groupByParent ($array)
{
$groups = array();
foreach ($array as $a) {
$groups[$a['parent']][] = $a;
}
return $groups;
}
function insideSort ($array)
{
foreach ($array as $k => $v) {
usort($array[$k], function($a, $b){
return $a['id'] == $b['parent'] ? -1 : 1;
});
$f = array_shift($array[$k]);
sort($array[$k]);
array_unshift($array[$k], $f);
}
return $array;
}
function finalSort($array)
{
$final = array();
foreach ($array as $a) {
$final = array_merge($final, $a);
}
return $final;
}
$grr = groupByParent($arr);
$irr = insideSort($grr);
ksort($irr);
$res = finalSort($irr);
Is there an easier way to achieve it?
Explanation
Another way to sort the array, could be iterating through all elements in the array, and find all distinct parents, then store all siblings for each parent found, except for the once that has id same as parent. Then we sort it ascending and prepend the node that has id same as parent, to the start of the array.
Big O notation
The run time for this algorithm will have a best case of O(n), and a worst case of O(n^2).
Code
Execution time
Result was found using microtime(true) at top and bottom of code and subtracting the end time from the start time.
Conclusion
So the code I provided is not neccessarily an easier way to achieve what you want, however it looks like it's a little bit more efficient especially when using small arrays like the one in the code above.
I have not tested execution time on big arrays and would advice you to do so before choosing a solution.
And if you manage to figure out a way to get rid of the "Display properly" part (line 48-50 in my code) and instead store the data properly from start to end, the execution time would improve alot.
Good luck, and happy new year!