Как превратить эту функцию, чтобы быть рекурсивным с многомерным массивом? - PullRequest
0 голосов
/ 30 октября 2018

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

id belongs_to
1a  NULL
2a  NULL
3a  1a
4a  NULL
5a  2a

И нерекурсивная функция типа:

foreach ($first_layer as $first_layer_obj) {
        $array[$first_layer_obj->id] = [];
        $second_layer = /* SELECT id FROM client WHERE belongs_to $first_layer_obj->id */;
        foreach ($second_layer as $second_layer_obj) {
            $array[$first_layer_obj->id][$second_layer_obj->id] = [];
            $third_layer = /* SELECT id FROM client WHERE belongs_to $second_layer_obj->id */;
            foreach ($third_layer as $third_layer_obj->id) {
                $array[$first_layer_obj->id][$second_layer_obj->id][$third_layer_obj->id] = [];
            }
        }

Я ожидаю, что результат будет:

array(3) {
["1a"]=>
   array(1){
     ["3a"]=>[]
   }
["2a"]=>
   array(1){
     ["5a"]=>[]
   }
["4a"]=>[]
}

1 Ответ

0 голосов
/ 31 октября 2018

Конечно, первый совет, который я имею, заключается в том, что вам следует избегать выполнения рекурсивных / повторных вызовов вашей базы данных. Вы должны сделать один вызов, чтобы извлечь все нужные строки в одном наборе результатов и позволить php выполнить сложную часть.

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

[см. Встроенные комментарии о том, что происходит в моем сценарии]

* Если вы не используете php7 +, то мой нулевой оператор объединения ($row1['children'] ?? []) вызовет проблемы.
Вы можете использовать: (isset($row1['children']) ? $row1['children'] : []

Код: ( Демо )

// use ORDER BY belongs_to DESC, id ASC ... or usort() to prepare result set
$resultset = [
    ['id' => '6a', 'belongs_to' => '5a'],
    ['id' => '5a', 'belongs_to' => '3a'],
    ['id' => '8a', 'belongs_to' => '3a'],
    ['id' => '3a', 'belongs_to' => '1a'],
    ['id' => '1a', 'belongs_to' => null],
    ['id' => '2a', 'belongs_to' => null],
    ['id' => '4a', 'belongs_to' => null],
    ['id' => '7a', 'belongs_to' => null]
];

foreach ($resultset as $index1 => &$row1) {             // make input array modifiable by reference (not working with a copy)
    if ($row1['belongs_to']) {                          // original belongs_to value is not null (not a top-level parent)
        foreach ($resultset as $index2 => $row2) {      // search for targeted parent
            if ($row2['id'] == $row1['belongs_to']) {   // parent found
                $resultset[$index2]['children'][] = [$row1['id'] => $row1['children'] ?? []];  // store original row as child
                unset($resultset[$index1]);             // remove original row (no reason to iterate it again in outer loop)
                break;                                  // halt inner loop (no reason to iterate further)
            }
        }
    } else {                                            // original belongs_to value is null (top-level parent)
        $output[$row1['id']] = $row1['children'] ?? [];  // store children to top
    }
}
var_export($output);

Выход:

array (
  '1a' => 
  array (
    0 => 
    array (
      '3a' => 
      array (
        0 => 
        array (
          '5a' => 
          array (
            0 => 
            array (
              '6a' => 
              array (
              ),
            ),
          ),
        ),
        1 => 
        array (
          '8a' => 
          array (
          ),
        ),
      ),
    ),
  ),
  '2a' => 
  array (
  ),
  '4a' => 
  array (
  ),
  '7a' => 
  array (
  ),
)
...