Иерархический массив PHP - Родители и дети

Я использую PHP и mySQL с Idiorm. Это может быть не актуально.

Мой массив PHP

  • Это отношения между родителями и детьми.
  • 0 является родительским корнем.
  • Пример. Корневой родительский 0 имеет дочерний элемент 33, у которого есть дочерний элемент 27, который имеет ребенок 71.

Эта структура массива может быть изменена, если это необходимо для решения проблемы.

array (
  33 => 
    array (
      0 => '27',
      1 => '41',
  ),
  27 => 
    array (
      0 => '64',
      1 => '71',
  ),
  0 => 
    array (
      0 => '28',
      1 => '29',
      2 => '33',
  ),
)

Мой иерархический результат

Что-то вроде этого, но как массив...

  0 => 
      28
      29
      33
         27 =>
               64
               71
         41

Информация

  • Глубина не определена и может быть неограниченной. Я попробовал foreach, но это может быть не так.

Мои собственные мысли

  • Некоторая рекурсивная функция?
  • Некоторые из циклов?

Я попробовал оба из вышеперечисленного, просто получил беспорядок. Это просто.

Ответы

Ответ 1

Предложение от @deceze сработало. Однако входной массив должен изменить litte, как это...

$rows = array(
    array(
        'id' => 33,
        'parent_id' => 0,
    ),
    array(
        'id' => 34,
        'parent_id' => 0,
    ),
    array(
        'id' => 27,
        'parent_id' => 33,
    ),
    array(
        'id' => 17,
        'parent_id' => 27,
    ),
);

Из fooobar.com/questions/87443/...:

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;
}

$tree = buildTree($rows);

print_r( $tree );

Ответ 2

Я добавил в @Jens Törnell ответы, чтобы включить определение параметров имени столбца parent_id, имени ключа дочернего массива, а также имени столбца для id.

/**
 * function buildTree
 * @param array $elements
 * @param array $options['parent_id_column_name', 'children_key_name', 'id_column_name'] 
 * @param int $parentId
 * @return array
 */
function buildTree(array $elements, $options = [
    'parent_id_column_name' => 'parent_id',
    'children_key_name' => 'children',
    'id_column_name' => 'id'], $parentId = 0)
    {
    $branch = array();
    foreach ($elements as $element) {
        if ($element[$options['parent_id_column_name']] == $parentId) {
            $children = buildTree($elements, $options, $element[$options['id_column_name']]);
            if ($children) {
                $element[$options['children_key_name']] = $children;
            }
            $branch[] = $element;
        }
    }
    return $branch;
}

Поскольку функциональность довольно универсальная, мне удалось использовать указанную выше функцию в большинстве моих проектов.

Ответ 3

отличный ответ от @Jens Törnell, просто хотел добавить небольшое усовершенствование, которое, если ваш parent_id и id на самом деле являются строкой вместо числа, тогда выше метод завершится неудачно и после создания дочернего массива он снова создаст эти дочерние массивы как отдельный индивидуальный массив. Чтобы исправить это, вы должны сделать тройную равную проверку и путем сопоставления типа данных переменной i.e(string).

Идентификаторы на основе строк и Parent_id в массиве

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

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

    return $branch;
}

дополнительно, если кто-то захочет, он может добавить третий параметр для работы, чтобы динамически указывать тип данных переменных i.e function buildTree(array $elements, $parentId = 0, $datatype='string'), но тогда вам придется брать любую другую ошибку.

надеюсь, что это поможет кому-то!