добавление еще одного уровня в иерархический многомерный массив

Обновить:

Вот плоский массив, полученный из mysql. Я использую таблицу закрытия для хранения иерархических отношений:

Array
(
[0] => Array
(
[brand] => Intel
[id] => 53
[name] => CPU 1978
[parent_id] => 0
)

[1] => Array
(
[brand] => Asus
[id] => 537
[name] => CPU 1999
[parent_id] => 53
)

[2] => Array
(
[brand] => HTC
[id] => 538
[name] => CPU 1998
[parent_id] => 53
)
)

У меня есть некоторые данные, показывающие, на каких древних продуктах основаны новые продукты. Я использую следующий код для преобразования плоского массива в иерархический многомерный массив:

function buildTree(array $elements, $parentId = 0) {
$branch = array();

foreach ($elements as $element) {
if ($element['parent_id'] == $parentId) {
$children = buildTree($elements, $element['id']);
if ($children) {
$element['children'] = $children;
}
$branch[] = $element;
}
}

return $branch;
}

Результат:

Array
(
[0] => Array
(
[brand] => Intel
[id] => 53
[name] => CPU 1978
[parent_id] => 0
[children] => Array
(
[0] => Array
(
[brand] => Asus
[id] => 537
[name] => CPU 1999
[parent_id] => 53
)

[1] => Array
(
[brand] => HTC
[id] => 538
[name] => CPU 1998
[parent_id] => 53
)

)

)

)

Я хочу реорганизовать дерево, добавив новый ключ brands на первый уровень и извлеките детские бренды в виде ключей массива второго уровня, например:

Array
(
[0] => Array
(
[brand] => Intel
[id] => 53
[name] => CPU 1978
[parent_id] => 0
[brands]=> Array
(
[Asus]=> Array
(
[0] => Array
(
[id] => 537
[name] => CPU 1999
[parent_id] => 53
)
)

[HTC] => Array
(
[0]=>Array
(
[id] => 538
[name] => CPU 1998
[parent_id] => 53
)
)
[Intel]=>Array() // Keep this one for new CPU from Intel
))

)

Я попытался создать еще одну функцию для вставки брендов в родительские уровни, но моя проблема в том, как я могу поместить детский процессор в соответствующие бренды?

function brand(array $elements,$children){
$branch = array();
foreach($elements as $k=>$element){
/* if($element['brand'] == $children['brand']) not working **/
$branch[$element['brand']] = $children;
}
return $branch;
}

function buildTree(array $elements, $parentId = 0) {
$branch = array();

foreach ($elements as $element) {
if ($element['parent_id'] == $parentId) {
$children = buildTree($elements, $element['id']);
if ($children) {
$element['brands'] = brand($elements,$children);

}
$branch[] = $element;
}
}

return $branch;
}

Это дает мне такой результат:

 Array
(
[0] => Array
(
[brand] => Intel
[id] => 53
[name] => CPU 1978
[parent_id] => 0
[brands]=> Array
(
[Asus]=> Array
(
[0] => Array
(
[brand]=> Asus
[id] => 537
[name] => CPU 1999
[parent_id] => 53
)
[1]=>Array
(
[brand]=>HTC
[id] => 538
[name] => CPU 1998
[parent_id] => 53
)
)

[HTC] => Array
(
[0] => Array
(
[brand]=> Asus
[id] => 537
[name] => CPU 1999
[parent_id] => 53
)
[1]=>Array
(
[brand]=>HTC
[id] => 538
[name] => CPU 1998
[parent_id] => 53
)
)
[Intel]=>Array(
(
[0] => Array
(
[brand]=> Asus
[id] => 537
[name] => CPU 1999
[parent_id] => 53
)
[1]=>Array
(
[brand]=>HTC
[id] => 538
[name] => CPU 1998
[parent_id] => 53
)
)
)
))

)

1

Решение

RedGiant, следующая функция примет вывод вашего существующего buildTree() метод и рекурсивно преобразовать его таким образом, чтобы все children элементы в массиве дерева будут заменены на brands:

function brand(array $elements)
{
// Return early if parent has no children
if (! array_key_exists('children', $elements)) {
return $elements;
}

// Initialise local values
$brands = array();

// Transform children (recursively)
foreach ((array) $elements['children'] as $child) {
$brand = $child['brand'];
unset($child['brand']);

// Use call_user_func() and __function__ to prevent name dependency
// within the function itself. If required, this can be replaced with:
// $brands[$brand] = array(brand($child);
$brands[$brand] = array(call_user_func(__function__, $child));
}

// Replace children with brands
unset($elements['children']);
$elements['brands'] = $brands;

return $elements;
}

Функция должна быть вызвана через array_map()т.е.

$old_tree = buildTree($original_flat_array)
$new_tree = array_map('brand', buildTree($original_flat_array));

Преимущество этого решения в том, что оно сохраняет все существующие ключи массива (кроме childrenочевидно). Таким образом, любой ключ, который вы можете добавить к исходному плоскому массиву в будущем, будет перенесен в новое преобразованное дерево массивов без необходимости модификации кода.

1

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

Изменить: Мой предыдущий ответ не удался, когда было несколько дочерних элементов для бренда. Ниже приведено гораздо более надежное решение.

function buildTree(array $elements, $parentId = 0)
{
$branch = [];

foreach ($elements as $element) {
if ($element['parent_id'] == $parentId) {
$element['brands'] = brand(buildTree($elements, $element['id']));

$branch[] = $element;
}
}

return $branch;
}

function brand(array $elements)
{
$branch = [];
foreach ($elements as $element) {
$branch[$element['brand']][] = [
'id' => $element['id'],
'name' => $element['name'],
'parent_id' => $element['parent_id'],
];
}

return $branch;
}

Это возвращает следующее из исходного массива:

Array
(
[0] => Array
(
[brand] => Intel
[id] => 53
[name] => CPU 1978
[parent_id] => 0
[brands] => Array
(
[Asus] => Array
(
[0] => Array
(
[id] => 537
[name] => CPU 1999
[parent_id] => 53
)
)
[HTC] => Array
(
[0] => Array
(
[id] => 538
[name] => CPU 1998
[parent_id] => 53
)
)
)
)
)
2

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