Отличная попытка и очень на правильном пути. Проблема с рекурсией в компараторе заключается в том, что usort
не будет вызывать функцию компаратора, когда длина массива равна 1, поэтому независимо от того, исследуете ли вы все дерево или нет, вы хотите получить значение usort
. Это оставит ветку дерева id => 245982
.
Решение состоит в том, чтобы избежать повторного использования функции сравнения usort
напрямую. Вместо этого используйте обычную рекурсивную функцию, которая при необходимости вызывает usort
, а именно текущий или дочерний массив содержит целевой идентификатор. Я использую отдельный массив для отслеживания того, какие элементы должны быть перемещены вперед, но вы можете выйти из цикла и соединить / отодвинуть один элемент вперед, если вы предпочитаете.
Мы также можем сделать $category_id
параметром для функции.
Вот один из подходов:
function reorder_tree_r(&$children, $target) {
$order = [];
$should_sort = false;
foreach ($children as $i => &$child) {
$order[$i] = false;
if (array_key_exists("children", $child) &&
reorder_tree_r($child["children"], $target) ||
$child["id"] === $target) {
$order[$i] = true;
$should_sort = true;
}
}
if ($should_sort) {
$priority = [];
$non_priority = [];
for ($i = 0; $i < count($children); $i++) {
if ($order[$i]) {
$priority[]= $children[$i];
}
else {
$non_priority[]= $children[$i];
}
}
$children = array_merge($priority, $non_priority);
}
return $should_sort;
}
function reorder_tree($tree, $target) {
if (!$tree || !array_key_exists("children", $tree)) {
return $tree;
}
reorder_tree_r($tree["children"], $target);
return $tree;
}
var_export(reorder_tree($tree, 225902));
Выход:
array (
'id' => 245974,
'children' =>
array (
0 =>
array (
'id' => 245982,
'children' =>
array (
0 =>
array (
'id' => 246093,
'children' =>
array (
0 =>
array (
'id' => 225902,
),
1 =>
array (
'id' => 225892,
),
2 =>
array (
'id' => 225893,
),
),
),
),
),
1 =>
array (
'id' => 111,
),
),