Обновить:
Вот плоский массив, полученный из 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
)
)
)
))
)
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
очевидно). Таким образом, любой ключ, который вы можете добавить к исходному плоскому массиву в будущем, будет перенесен в новое преобразованное дерево массивов без необходимости модификации кода.
Изменить: Мой предыдущий ответ не удался, когда было несколько дочерних элементов для бренда. Ниже приведено гораздо более надежное решение.
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
)
)
)
)
)