Преобразовать плоский массив в дерево с одноразовым циклом

ТАК,

Проблема

Предположим, у нас есть плоский массив со следующей структурой:

$array = [
  ['level'=>1, 'name' => 'Root #1'],
  ['level'=>1, 'name' => 'Root #2'],
  ['level'=>2, 'name' => 'subroot 2-1'],
  ['level'=>3, 'name' => '__subroot 2-1/1'],
  ['level'=>2, 'name' => 'subroot 2-2'],
  ['level'=>1, 'name' => 'Root #3']
];

Проблема в том, чтобы преобразовать этот массив, чтобы он стал деревом. Подчиненность определяется только порядком элементов иlevel поле. Давайте определимсяchildren как имя измерения для хранения дочерних узлов. Для массива выше это будет:

  array (
    array (
      'level' => 1,
      'name' => 'Root #1',
    ),
    array (
      'level' => 1,
      'name' => 'Root #2',
      'children' => 
      array (
        array (
          'level' => 2,
          'name' => 'subroot 2-1',
          'children' => 
          array (
            array (
              'level' => 3,
              'name' => '__subroot 2-1/1',
            ),
          ),
        ),
        array (
          'level' => 2,
          'name' => 'subroot 2-2',
        ),
      ),
    ),
    array (
      'level' => 1,
      'name' => 'Root #3',
    ),
  )

Еще немного уточнений, если не очевидно, кто является родителем для кого: следующий код может легко визуализировать идею:

function visualize($array)
{
   foreach($array as $item)
   {
      echo(str_repeat('-', $item['level']).'['.$item['name'].']'.PHP_EOL);
   }
}
visualize($array);

-для массива выше это:

-[Root #1]
-[Root #2]
--[subroot 2-1]
---[__subroot 2-1/1]
--[subroot 2-2]
-[Root #3]

конкретика

Существуют некоторые ограничения как для желаемого решения, так и для входного массива:

Входной массиввсегда в силе: это означает, что его структура всегда может быть преобразована в древовидную структуру. Нет таких странных вещей, как отрицательные / нечисловые уровни, нет недопустимой структуры уровней и т. Д.Входной массив может быть огромным, и в настоящее время максимальный уровень не ограниченРешениедолжен решить вопрос сОдин цикл, поэтому мы не можем разделить массив на куски, применить рекурсию или каким-либо образом перейти в массив. Простоforeach (или другой цикл - это не имеет значения), только один раз, каждый элемент один за другим должен обрабатываться.

Мой подход

В настоящее время у меня есть решение со стеком. Я работаю со ссылками и поддерживаю текущий элемент стека, на который будет производиться запись на текущем шаге. Это:

function getTree(&$array)
{
   $level = 0;
   $tree  = [];
   $stack = [&$tree];
   foreach($array as $item)
   {
      if($item['level']>$level) //expand stack for new items
      {
         //if there are child elements, add last to stack:
         $top = key($stack);
         if(count($stack[$top]))
         {
            end($stack[$top]);
            $stack[] = &$stack[$top][key($stack[$top])];
         }
         //add ['children'] dim to top stack element
         end($stack);
         $top = key($stack);
         $stack[$top]['children'] = [];
         $stack[] = &$stack[$top]['children'];
      }
      while($item['level']<$level--) //pop till certain level
      {
         //two times: one for last pointer, one for ['children'] dim
         array_pop($stack);
         array_pop($stack);
      }
      //add item to stack top:
      end($stack);
      $stack[key($stack)][] = $item;
      $level = $item['level'];
   }
   return $tree;
}

-Так как это достаточно долго, я создалобразец использования и вывода.

Вопрос

Как видите, мое решение довольно длинное и основано на ссылках и обработке внутреннего указателя массива (такие вещи, какend()), таквопрос в том:

Может быть, есть другие - более короткие и ясные способы решения этой проблемы? Это выглядит как стандартный вопрос, но я не нашел соответствующего решения (есть одно подобноевопрос - но там точно есть ОПparent_id подчинения пока у меня нет)

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

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