Преобразовать простой массив в массив иерархии

Я делаю цикл по массиву ниже, который имеет несколько записей. В примере у меня есть 3 элемента, где каждый элемент имеет 3 значения внутри.

[0]
['name'] => 'aaa'
['id'] => 38679
['parent-id'] => 0
[1]
['name'] => 'bbb'
['id'] => 38830
['parent-id'] => 38679
[2]
['name'] => 'ccc'
['id'] => 38680
['parent-id'] => 38830

Итак, зацикливаясь на массиве, мне нужно построить еще один в этом формате (идея состоит в том, чтобы построить иерархию):

[0]
[38679] => 'aaa'
[38830] => 'bbb'
[38680] => 'ccc'

Может быть, есть другой способ сделать это. Любое предложение было бы здорово.

2

Решение

Одним из возможных решений является использование рекурсивной функции:

$test = [
0 => [
'name' => 'aaa',
'id' => 38679,
'parent-id' => 0
],
1 => [
'name' => 'bbb',
'id' => 38830,
'parent-id' => 38679
],
2 => [
'name' => 'ccc',
'id' => 38680,
'parent-id' => 38830
]
];

function make_hierarchy(array $arr, $parent = 0) {
$result = array();

foreach($arr as $item) {
if ($item['parent-id'] == $parent) {
$children = make_hierarchy($arr, $item['id']);
$child = $item;
if ($children) {
$child['children'] = $children;
}
$result[] = $child;
}
}
return $result;
}

$r = make_hierarchy($test);

var_dump($r);
1

Другие решения

Итеративное решение:

// set up test data
$arr = [
0 => [
'name' => 'aaa',
'id' => 38679,
'parent-id' => 0
],
1 => [
'name' => 'bbb',
'id' => 38830,
'parent-id' => 38679
],
2 => [
'name' => 'ccc',
'id' => 38680,
'parent-id' => 38830
]
];

// hierarchy array that will have the result
$hier = [];

// Start off by putting all nodes as top-level nodes in the hierarchy
foreach ($arr as $node) {
$node['children'] = [];
$hier[$node['id']] = $node;
};

// Iterate to move nodes from the top-level under their respective parents.
do {
$count = count($hier);
echo 'Next iteration: ', $count, ' top-level nodes left<br>';

// Collect the ids of parents of top-level nodes
$parents = [];
foreach ($hier as $node) {
$parents[$node['parent-id']] = 1;
}

// Find all nodes that are candidate to be moved
foreach ($hier as $node) {
// Treat node only if it has gathered all of its children
if (!array_key_exists($node['id'], $parents)) {
$parentId = $node['parent-id'];
// Remove the parent-id attribute, it is not needed anymore
unset($node['parent-id']);
// Remove the node from the top-level
unset($hier[$node['id']]);
// Check that referenced parent exists, parent-id=0 will fail this.
if (array_key_exists($parentId, $hier)) {
// Move this node under its parent node, keyed by its ID
echo 'Node ', $node['id'], ' moved under ', $parentId, '<br>';
$hier[$parentId]['children'][$node['id']] = $node;
} else {
// Node is stays on top-level (but without parent-id property):
echo 'Node ', $node['id'], ' stays at top level<br>';
$hier[] = $node;
}
}
};
// keep going as long as we were able to move at least one node
} while (count($hier) < $count);

echo 'Done. <pre>';
print_r($hier);
echo '</pre>';

Протестировано, с выводом:

Next iteration: 3 top-level nodes left
Node 38680 moved under 38830
Next iteration: 2 top-level nodes left
Node 38830 moved under 38679
Next iteration: 1 top-level nodes left
Node 38679 stays at top level
Done.

Array
(
[38831] => Array
(
[name] => aaa
[id] => 38679
[children] => Array
(
[38830] => Array
(
[name] => bbb
[id] => 38830
[children] => Array
(
[38680] => Array
(
[name] => ccc
[id] => 38680
[children] => Array
(
)
)
)
)
)
)
)
1

По вопросам рекламы [email protected]