рекурсивный обход дерева – Как отслеживать уровень рекурсии?

Я в основном пытаюсь построить html ul / li вложенный список из многомерного массива, представляющего древовидную структуру.

Следующий код работает нормально, но я хочу его улучшить:

Мне нужен способ отслеживать уровень рекурсии, чтобы я мог применять разные классы к разным уровням, добавлять отступы к сгенерированному выходу и т. Д.

function buildTree($tree_array, $display_field, $children_field, $class='', $id='') { echo "<ul>\n"; foreach ($tree_array as $row) { echo "<li>\n"; echo $row[$display_field] . "\n"; if (isset($row[$children_field])) { $this->buildTree($row[$children_field]); } echo "</li>\n"; } echo "</ul>\n"; } 

$ Tree_array выглядит так:

 Array ( [0] => Array ( [category_id] => 1 [category_name] => calculatoare [parent_id] => 0 [children] => Array ( [0] => Array ( [category_id] => 4 [category_name] => placi de baza [parent_id] => 1 ) [1] => Array ( [category_id] => 5 [category_name] => carcase [parent_id] => 1 [children] => Array ( [0] => Array ( [category_id] => 6 [category_name] => midi-tower [parent_id] => 5 ) ) ) ) ) [1] => Array ( [category_id] => 2 [category_name] => electronice [parent_id] => 0 ) [2] => Array ( [category_id] => 3 [category_name] => carti [parent_id] => 0 ) ) 

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

Solutions Collecting From Web of "рекурсивный обход дерева – Как отслеживать уровень рекурсии?"

Quick'n'dirty подход (см. Блок «spoiler» ниже для реализации):

Добавьте дополнительную переменную $recursionDepth в объявление функции, по умолчанию сделайте ее 0.

На каждой последующей рекурсии вызовите свою функцию с помощью $recursionDepth + 1 .

Поскольку функциональные переменные являются только «видимыми» (областями) для соответствующего экземпляра функции, вы получите индикатор текущей итерационной глубины.

Кроме того, строка 12 вашей функции

 $this->buildTree(); 

не выглядит так, как если бы это сработало – причина в том, что вы не передаете переменные на следующий экземпляр buildTree.

Вероятно, это должно выглядеть так:

 $this->buildTree($row[$children_field], $display_field, $children_field, $class, $id) 

Вот изменения, которые я внес в ваш код, чтобы добиться того, чего вы хотите:

 function buildTree($tree_array, $display_field, $children_field, $class='', $id='', $recursionDepth = 0, $maxDepth = false) { if ($maxDepth && ($recursionDepth == $maxDepth)) return; echo "<ul>\n"; foreach ($tree_array as $row) { echo "<li>\n"; echo $row[$display_field] . "\n"; if (isset($row[$children_field])) $this->buildTree($row[$children_field], $display_field, $children_field, $class, $id, $recursionDepth + 1, $maxDepth); echo "</li>\n"; } echo "</ul>\n"; } 

Вы делаете свою жизнь труднее, чем нужно. SPL предлагает несколько итераторов для вашего удобства. Пересечение многомерных массивов легко с классом RecursiveArrayIterator . Он не только позволяет обрабатывать любые уровни глубинных массивов, но и отслеживать глубину.

пример

 $iterator = new RecursiveIteratorIterator( new RecursiveArrayIterator($array) ); for($iterator; $iterator->valid(); $iterator->next()) { printf( "Key: %s Value: %s Depth: %s\n", $iterator->key(), $iterator->current(), $iterator->getDepth() ); } 

Пример кода

Как вы можете видеть, существует метод getDepth() который всегда будет getDepth() текущую глубину итерации. Это метод RecursiveIteratorIterator необходимый для итерации над детьми в рекурсивных итераторах.

Если вам нужно влиять на то, что происходит, когда начинается итерация или когда обращаются к детям, взгляните на мой ответ на многомерную итерацию массива, в которой отображается пользовательский RecursiveIteratorIterator элемент, который будет переносить значения многомерного массива в элементы xml и отбрасывать их на глубину текущая итерация (которая должна быть тривиальной для адаптации к элементам ul / li).

Также взгляните на статью Википедии об Итераторах для общего введения.

 public virtual int GetLevelById(int id) { int i = GetParentById(id); if (i == 0) return 1; else return (1 + GetLevelById(i)); } 

public virtual int GetParentById (int t) {var ret = this._list.FirstOrDefault ((f) => f.Id == t); if (ret! = null) return ret.ParentId; return -1; }