рекурсия массива php

У меня есть такой массив:

Array ( 
[0] => Array ( [id] => 1000 [enroller_id] => 1005) 

[1] => Array ( [id] => 1005 [enroller_id] =>) 

[2] => Array ( [id] => 1101 [enroller_id] => 1000 ) 

[3] => Array ( [id] => 1111 [enroller_id] => 1000 ) 
)

Я хочу создать массив иерархии следующим образом:

Array(
[1005] => Array(
               [1000] => Array(
                              [1101] => ...
                              [1111] => ...
                              )
               )
)

Вы можете мне помочь? Я думаю, что это рекурсия.

Ответы на вопрос(2)

//$paths is an array of references, in which _every_ item will sit at 'root'
//level, but also as a reference as a child to it's parent.

//initialize location of parentless / root items:
$paths = array('N'=>array());

foreach($items as $item){
    //$target is the parent-id, or 'N' if we are a root node
    $target = isset($item['enroller_id']) && !empty($item['enroller_id']) ? $item['enroller_id'] :'N';

    //if the parent is not yet in the paths array, make an entry for it
    if(!isset($paths[$target]))      $paths[$target] = array();

    //if this item is not yet in the array (the previous statement could  
    //already have inserted it, make an array(
    if(!isset($paths[$item['id']]))  $paths[$item['id']] = array();

    //add the current item as a reference to it's parent
    $paths[$target][$item['id']] =  &$paths[$item['id']];

    //Setting it as a reference has this consequence:
    //   when adding an item to the $paths[$id] array, it will 
    //   automatically be added to $paths[$parent][$id], as 
    //   both $paths[$id] & $paths[$parent][$id] point to the same
    //   location in memory.
    //   This goes to infinite depth: if $foo is a child of $id, and you
    //   add a node to it, it will be in
    //   $paths[$foo]               = array($child);
    //   $paths[$id][[$foo]         = array($child);
    //   $paths[$parent][$id][$foo] = array($child);
    //
    //   Altering an item at any location in paths / the tree will alter it anywhere
    //   in the paths / tree, unsetting it anywhere only unset the data at that location, 
    //   other locations will still have the same data (and the data will keep 
    //   existing until the last reference is unset())

}
//we are only interested in the 'root' nodes (all other nodes should be subnodes
//in this tree
$tree = $paths['N'];
//remove all unused references in the $paths array
//do remember to do this: cleaning up references is important
unset($paths);
//tree is now an array of 'normal' values (i.e. only 1 reference to each datapoint exists
var_dump($tree);

Не забудьunset пути: ссылки могут действительно укусить вас трудно прослеживаемыми ошибками, если вы не будете должным образом заботиться

 Alex Pliutau23 сент. 2010 г., 11:34
Это не очень хорошее решение.
 Matthew23 сент. 2010 г., 11:48
Лучший способ получить быстрое приложение - использовать правильные алгоритмы. Это было первое решение, которое пришло мне в голову. Кажется почти тривиальным ...
 Sjoerd23 сент. 2010 г., 11:40
Это не так ясно. Хотя это решение довольно сложно понять, оно перебирает массив только один раз. Это делает его намного быстрее, чем рекурсивное решение, если у вас большое дерево.
 Wrikken23 сент. 2010 г., 11:39
Добавлены комментарии к решению для объяснения. @ Alexander.Plutov: хотите сказать мне, почему? Никакого дублирования данных, только один цикл, довольно эффективный, и никаких ссылок, лежащих в конце. В качестве дополнительного бонуса,заказ товаров не имеет значения: вы можете иметь ребенка на входе задолго до родителя, и этобудут все еще работают.
 Sjoerd23 сент. 2010 г., 11:22
Можете ли вы объяснить, как это работает?
 Wrikken23 сент. 2010 г., 11:53
ИМХО, только если «не ясно», если не знать, что это за ссылки. К сожалению, это не всегда так для программистов PHP, но я считаю, что онидолжен знать о тех. Непонимание основ языка не является основанием для изменения ответов лично для меня. Да, пишите четко читаемый код, и могут быть предприняты незначительные потери производительности, чтобы сделать код более понятным и обслуживаемым, но, на мой взгляд, это не так.
 Matthew23 сент. 2010 г., 11:31
Он просто связывает текущий узел и его родительский узел на каждой итерации. В начале у вас просто есть два осиротевших узла. В конце концов они соединяются вместе, пока вы не получите окончательное дерево. Единственный побочный эффект заключается в том, что неисключенные узлы будут игнорироваться, но это не является ошибкой алгоритма.
Решение Вопроса

Это будет делать то, что вы хотите, за исключением того, что не помещает первый элемент (1005) в массив:

function create_array($number, $data)
{
    $result = array();
    foreach ($data as $row)
    {
        if ($row['enroller_id'] == $number)
        {
            $result[$row['id']] = create_array($row['id'], $data);
        }
    }
    return $result;
}

print_r(create_array(1005, $data));

Выход:

Array
(
    [1000] => Array
        (
            [1101] => Array ()
            [1111] => Array ()
        )
)
 Joko Wandiro26 окт. 2011 г., 16:27
+1, отличная рекурсия, теперь я могу легко создать динамический вложенный массив.
 Matthew23 сент. 2010 г., 11:43
1005 следует заменить на ноль, и тогда это будет работать. И, как это часто бывает, рекурсия проста, но вызывает чрезмерные итерации.
 Alex Pliutau23 сент. 2010 г., 11:23
Благодарю. Это идеальное решение!
 Wrikken23 сент. 2010 г., 11:37
Откуда мы волшебным образом знаем 1005? И не должно ли это быть в результате?

Ваш ответ на вопрос