Reputation: 1281
I would like sort a given array of categories. The root categories must appear first before their child categories in a new array.
Example data:
$data = [
['id' => '1', 'name' => 'abc', 'parent_id' => '0' ],
['id' => '4', 'name' => 'def', 'parent_id' => '5' ],
['id' => '3', 'name' => 'ghj', 'parent_id' => '2' ],
['id' => '5', 'name' => 'zst', 'parent_id' => '1' ],
['id' => '2', 'name' => 'klm', 'parent_id' => '1' ],
];
Output I would like to achieve:
$output = [
'1' => ['id' => '1', 'name' => 'abc', 'parent_id' => '0' ],
'5' => ['id' => '5', 'name' => 'zst', 'parent_id' => '1' ],
'4' => ['id' => '4', 'name' => 'def', 'parent_id' => '5' ],
'2' => ['id' => '2', 'name' => 'klm', 'parent_id' => '1' ],
'3' => ['id' => '3', 'name' => 'ghj', 'parent_id' => '2' ],
];
My code until now:
function sortCategories($data) {
$output = [];
foreach ($data as $category) {
if ($output[$category['id']] || $output[$category['parent_id']])
continue;
if (!$output[$category['parent_id']])
$output = getParentCategories($category, $ouput, $data);
$output[$category['id']] = [
'id' => $category['id'],
'name' => $category['name'],
'parent_id' => $category['parent_id']
];
}
return $output;
}
function getParentCategories($category, $output, $data) {
if ($output[$category['parent_id']]) {
return $output;
} else {
}
}
The problem I have is that I don't know how to probably implement getParentCategories() so that this function handles root categories the right way.
Any suggestions how to solve the problem?
Upvotes: 1
Views: 143
Reputation: 72299
A solution using foreach()
will work for you:-
<?php
$data = [
['id' => '1', 'name' => 'abc', 'parent_id' => '0' ],
['id' => '4', 'name' => 'def', 'parent_id' => '5' ],
['id' => '3', 'name' => 'ghj', 'parent_id' => '2' ],
['id' => '5', 'name' => 'zst', 'parent_id' => '1' ],
['id' => '2', 'name' => 'klm', 'parent_id' => '1' ],
]; // original array
$new_array = array(); // new empty array
foreach($data as $key=>$value){ // iterate through original array
if($value['parent_id'] == 0){ // check root value
$new_array[$value['id']] = $value; // assign full sub-array to newly created array
}else{ // if not root value
$get_key = searchForId($value['parent_id'],$data); // based on parent-id get the parent array key from original array
$new_array[$data[$get_key]['id']] = $data[$get_key]; // based on key assign parent array to the newly created array
$new_array[$value['id']] = $value; // assign the child array to newly created array
}
}
function searchForId($id, $array) { // send parent_id and original array
foreach ($array as $key => $val) {
if ($val['id'] === $id) {
return $key; // return key of parent id
}
}
return null;
}
echo "<pre/>";print_r($new_array); // print new array
?>
Output:- https://eval.in/599837
Upvotes: 1
Reputation: 3049
Since php 7 we can use the spaceship operator like this
usort($output, function ($a,$b) {
return $a['parent_id'].$a['id'] <=> $b['parent_id'].$b['id'];
});
Both id's are concatenated so that id
and parent_id
are sorted and parent_id
has priority over id
.
In a real case, the id
's may have a range > 0..9 and you want 5 < 12, which is not the case when comparing strings as in the code above. Maybe you can post a code that takes that into account and have us review it. Maybe also learn about the difference between '1' => ['id' => '1']
and 1 => ['id' => 1]
first.
Upvotes: 1