<?php
$data = [
[
'table' => 'test',
'parent_table' => NULL,
],
[
'table' => 'test',
'parent_table' => NULL,
],
[
'table' => 'test2',
'parent_table' => 'test',
],
[
'table' => 'test4',
'parent_table' => NULL,
],
[
'table' => 'test5',
'parent_table' => 'test3',
],
[
'table' => 'test6',
'parent_table' => 'test5',
],
[
'table' => 'test3',
'parent_table' => 'test',
],
];
function reorderHierarchy($data){
$hierarchy = [];
$top_level_parents = [];
foreach($data as $each_data){
$hierarchy[$each_data['table']] = array();
if(is_null($each_data['parent_table'])){
if(!isset($top_level_parents[$each_data['table']])){
$top_level_parents[$each_data['table']] = 0;
}
$top_level_parents[$each_data['table']]++;
}
}
foreach($data as $each_data){
if(!is_null($each_data['parent_table'])){
$hierarchy[$each_data['parent_table']][] = $each_data['table'];
}
}
$result = [];
traverseHierarchy($hierarchy,$top_level_parents,$result);
return $result;
}
function traverseHierarchy($hierarchy,$top_level_parents,&$result){
foreach($top_level_parents as $each_parent => $occurrences){
while($occurrences-- > 0){
$result[] = [
'table' => $each_parent,
'parent_table' => NULL
];
}
traverseChildren($hierarchy,$each_parent,$result);
}
}
function traverseChildren($hierarchy,$parent,&$result){
foreach($hierarchy[$parent] as $each_child){
$result[] = [
'table' => $each_child,
'parent_table' => $parent
];
traverseChildren($hierarchy,$each_child,$result);
}
}
foreach(reorderHierarchy($data) as $each_data){
echo $each_data['table']," , ",(is_null($each_data['parent_table']) ? "NULL" : $each_data['parent_table']),"<br/>";
}
Выход:
test , NULL
test , NULL
test2 , test
test3 , test
test5 , test3
test6 , test5
test4 , NULL
Демо: https://3v4l.org/AmJpY
Пояснение:
Часть 1:
function reorderHierarchy($data){
$hierarchy = [];
$top_level_parents = [];
foreach($data as $each_data){
$hierarchy[$each_data['table']] = array();
if(is_null($each_data['parent_table'])){
if(!isset($top_level_parents[$each_data['table']])){
$top_level_parents[$each_data['table']] = 0;
}
$top_level_parents[$each_data['table']]++;
}
}
foreach($data as $each_data){
if(!is_null($each_data['parent_table'])){
$hierarchy[$each_data['parent_table']][] = $each_data['table'];
}
}
$result = [];
traverseHierarchy($hierarchy,$top_level_parents,$result);
return $result;
}
В вышеприведенной функции мы создаем 2 вида массивов, а именно $hierarchy
и $top_level_parents
. $hierarchy
- это массив, в котором каждый ключ содержит дочерние ключи. $top_level_parents
- это массив, который собирает все таблицы, у которых нет родителей, ключом является имя таблицы, а значением - ее вхождения.
Затем мы вызываем другую функцию traverseHierarchy
, чтобы пройти через всех этих родителей высшего уровня и получить их детей. Таким образом, мы всегда будем посещать родителей раньше, чем детей, так как мы сначала перебираем родителей (даже для детей, которые в свою очередь будут родителями для других таблиц).
Чтобы лучше объяснить, оба массива будут выглядеть примерно так:
$ иерархия:
Array
(
[test] => Array
(
[0] => test2
[1] => test3
)
[test2] => Array
(
)
[test4] => Array
(
)
[test5] => Array
(
[0] => test6
)
[test6] => Array
(
)
[test3] => Array
(
[0] => test5
)
)
$ top_level_parents:
Array
(
[test] => 2
[test4] => 1
)
Часть 2:
function traverseHierarchy($hierarchy,$top_level_parents,&$result){
foreach($top_level_parents as $each_parent => $occurrences){
while($occurrences-- > 0){
$result[] = [
'table' => $each_parent,
'parent_table' => NULL
];
}
traverseChildren($hierarchy,$each_parent,$result);
}
}
Здесь мы перебираем всех родителей верхнего уровня, сохраняя их в массиве result
с помощью no. раз они встречались в исходном массиве.
Как только мы это сделаем, мы бы теперь проследили за его дочерними элементами и включили все его дочерние элементы в массив результатов.
Часть 3:
function traverseChildren($hierarchy,$parent,&$result){
foreach($hierarchy[$parent] as $each_child){
$result[] = [
'table' => $each_child,
'parent_table' => $parent
];
traverseChildren($hierarchy,$each_child,$result);
}
}
Здесь мы перебираем все дочерние элементы и включаем их в result
. Вполне возможно, что у этого ребенка могут быть и собственные дети. Таким образом, мы рекурсивно собираем их все, используя поиск в глубину . Таким образом, мы всегда заботимся о том, чтобы родитель был раньше ребенка.
В последнем разделе мы просто выводим результат.