Код (Text): $array = array( 0 => array( 'id' => 15, 'pid' => 0, 'module_id' => 1, 'igordata' => array( 0 => array( 'id' => 16, 'pid' => 15, 'module_id' => 'comments1' ), 1 => array( 'id' => 21, 'pid' => 16, 'module_id' => 'comments1' ) ) ) ); function recur($what, $where, $level = 0) { $level++; foreach ($where as $entry) { if (isset($entry['id']) AND $entry['id'] == $what) { return $level; } else { if (isset($entry['igordata'])) { return recur($what, $entry['igordata'], $level); } } } return false; } var_dump(recur(21, $array));
[vs], Код (Text): $v = current($array); while (is_array($v)) { $level++; $v = current($array); } Ваш пример считает до бесконечности. А точнее, до превышения ограничения по времени. В том виде, как его подправил топикстартер, он действительно считает то, что нужно. Дмитрий, код [vs], который Вы поправили, все правильно считает. У id21 предок id16, а не id15, поэтому и получается 1, 2, 3.
igordata спасибо за код, но...я в самом первом посте написал: ну вобщем любой элемент, ибо функция должна быть универсальной, вычислять любой уровень вложенности... если бы задача стояла вычислить какой то конкретные массив, "руками" бы перебрал да вычислил asokol к сожалению не правильно она считает, привожу еще раз код: Имеем массив: Код (Text): Array ( [0] => Array ( [id] => 15 [pid] => 0 [nodes] => Array ( [0] => Array ( [id] => 32 [pid] => 15 ) [1] => Array ( [id] => 16 [pid] => 15 [nodes] => Array ( [0] => Array ( [id] => 30 [pid] => 16 [nodes] => Array ( [0] => Array ( [id] => 31 [pid] => 30 ) ) ) ) ) ) ) ) далее пытаемся считать: Код (Text): $tree = array(); $nodes = array(); $keys = array(); while ($row = mysql_fetch_assoc($result)) { $nodes[$row['id']] =& $row; //заполняем список веток записями из БД $keys[] = $row['id']; //заполняем список ключей(ID) unset($row); } $level = 0; foreach ($keys as $key) { // если нашли главную ветку(или одну из главных), то добавляем её в дерево if ($nodes[$key]['pid'] === '0') $tree[] =& $nodes[$key]; // else находим родительскую ветку и добавляем текущую ветку к дочерним элементам родит.ветки. else { if (isset($nodes[ $nodes[$key]['pid'] ])) //на всякий случай, вдруг в базе есть потерянные ветки { if (! isset($nodes[ $nodes[$key]['pid'] ]['nodes'])) //если нет поля определяющего наличие дочерних веток $nodes[ $nodes[$key]['pid'] ]['nodes'] = array(); //то добавляем к записи узел (массив дочерних веток) на данном этапе $nodes[ $nodes[$key]['pid'] ]['nodes'][] =& $nodes[$key]; } } $v = current($nodes); while (is_array($v)) { $level++; $v = current($v); echo $level."|<br>"; } } на выходе в $level имеем: Код (Text): 1| 2| 3| 4| 5| а надо что бы получилось Код (Text): 1| 2| 2| 3| 4| что я делаю не так? (ну понятно что все и надо идти читать мануалы...но все же?)
внес Код (Text): foreach ($keys as $key) { $level = 0; на выходе Код (Text): 1| 1| 1| 1| 1| я вот думаю, а может проще Код (Text): while ($row = mysql_fetch_assoc($result)) {; $items[] = $row;; } // это $items Array ( [0] => Array ( [id] => 15 [pid] => 0 ) [1] => Array ( [id] => 16 [pid] => 15 ) [2] => Array ( [id] => 30 [pid] => 16 ) [3] => Array ( [id] => 31 [pid] => 30 ) [4] => Array ( [id] => 32 [pid] => 15 ) ) и как-то по pid считать....но боюсь это даже говнокодней чем я до этого написал ))) Что-то мне подсказывает, что должно быть какое-то очень простое решение как получить из БД дерево имея id и parent_id.....
Да, вы правы, код [vs] не делает того, что нужно. Я посмотрел Ваш код, вот он (в том виде, в котором мне проще): Код (Text): $tree = array(); $nodes = array(); $keys = array(); while ($row = mysql_fetch_assoc($result)) { $nodes[$row['id']] =& $row; //заполняем список веток записями из БД $keys[] = $row['id']; //заполняем список ключей(ID) unset($row); } foreach($keys as $key) { // если нашли главную ветку(или одну из главных), то добавляем её в дерево if ($nodes[$key]['pid'] === '0') $tree[] =& $nodes[$key]; else { // else находим родительскую ветку и добавляем текущую ветку к дочерним элементам родит.ветки. if (isset($nodes[ $nodes[$key]['pid'] ])) { // на всякий случай, вдруг в базе есть потерянные ветки // если нет поля определяющего наличие дочерних веток // то добавляем к записи узел (массив дочерних веток) на данном этапе if (!isset($nodes[ $nodes[$key]['pid'] ]['nodes'])) $nodes[ $nodes[$key]['pid'] ]['nodes'] = array(); $nodes[ $nodes[$key]['pid'] ]['nodes'][] =& $nodes[$key]; } } } Если я правильно понимаю ситуацию, то надо посчитать вложенность для того, чтобы потом при выводе правильно разместить комментарии относительно их родителей. Если это так, то я не вижу смысла считать $level вообще. Лучше это сделать на этапе вывода. Потому что для вывода все равно придется пройтись по всем элементам.
если не сложно, в общих чертах не подскажите как? я вот еще подумал, а может все же на этапе ввода? <input type="hidden" id="level" name="level" value="%level%" /> первый комент: pid =0, level=0. дочкам этого комента при занесении в базу, плюсуем 1 к level... или неверный путь? (в любом случае сейчас попробую) попробовал, все чудненько, остался только один вопрос: как сделать так, что бы вот это Код (Text): $tree = array(); $nodes = array(); $keys = array(); while ($row = mysql_fetch_assoc($result)) { $nodes[$row['id']] =& $row; //заполняем список веток записями из БД $keys[] = $row['id']; //заполняем список ключей(ID) unset($row); } $level = 0; foreach($keys as $key) { // если нашли главную ветку(или одну из главных), то добавляем её в дерево if ($nodes[$key]['pid'] === '0') $tree[] =& $nodes[$key]; else { // else находим родительскую ветку и добавляем текущую ветку к дочерним элементам родит.ветки. if (isset($nodes[ $nodes[$key]['pid'] ])) { // на всякий случай, вдруг в базе есть потерянные ветки // если нет поля определяющего наличие дочерних веток // то добавляем к записи узел (массив дочерних веток) на данном этапе if (!isset($nodes[ $nodes[$key]['pid'] ]['nodes'])) $nodes[ $nodes[$key]['pid'] ]['nodes'] = array(); $nodes[ $nodes[$key]['pid'] ]['nodes'][] =& $nodes[$key]; } } } на выходе давало мне одномерный массив? Но ОБЯЗАТЕЛЬНО в том же порядке, в котором выводит сейчас
мдя...ларчик то просто открывался говорила мне мама, не слушай шибко умных и флудных даденек и так: при записи нового коммента в БД мы записывает level , равный +1 к имеющемуся. Если в корень коммент пишем ноль. далее выборка и обработка Код (Text): $tree = array(); $nodes = array(); $keys = array(); while ($row = mysql_fetch_assoc($result)) { $nodes[$row['id']] =& $row; $keys[] = $row['id']; unset($row); } foreach ($keys as $key) { $tree[] =& $nodes[$key]; } return $tree; в итоге на выходе одномерный массив в том порядке, в котором нам необходимо (хотя в этом у меня пока сомнения) ну а там уже по level делаем отступы..... ВСЕ ПОЛУЧИЛОСЬ, СПАСИБО!!!! а то рекурсия рекурсия ))))
я предполагал что это так, подскажите пожалуйста верное, если не сложно.... все же при выводу делать сортировку?
WTF, зачем здесь &? Для дерева надо простой цикл из моего примера заменить функцией, которую вызывать внутри её же до тех пор, пока не пройдет перебор всего дерева. Вот пример как делать рекурсию с помощью функции. Код (PHP): $arr = array(1,1,1,1,array(1,1,1,array(1,1),1,1,array(1,1,1),1)); function dub_arr($arr) { foreach ($arr as &$v) { $v = is_array($v) ? dub_arr($v) : $v * 2; } return $arr; } print_r(dub_arr($arr));
Код (PHP): $nodes = $pids = array(); // новые в конце $result = mysql_query("SELECT `id`, `pid`, `text` FROM `table` ORDER BY `id` ASC;"); while ($row = mysql_fetch_assoc($result)) { if (!isset($pids[$row['pid']])) $pids[$row['pid']] = array(); $pids[$row['pid']][] = $row['id']; $nodes[$row['id']] = $row; } unset($row); // раскомментировать, чтобы новые были в начале //$pids[0] = array_reverse($pids[0]); $tree = get_nodes($pids, 0); unset($pids); foreach($tree as $row) { print '<div style="padding-left:' . ($row['level']*20) . 'px;">' . $nodes[$row['id']]['text'] . '</a></div>'; } function get_nodes(&$pids, $pid, $level = 0) { foreach($pids[$pid] as $id) { $tree[] = array('id' => $id, 'level' => $level); if (!empty($pids[$id])) $tree = array_merge($tree, get_nodes($pids, $id, $level+1)); } return $tree; }
asokol моя благодарность не знает границ, но осмелюсь попросить еще подскажите, возможно ли как-то, на выходе, после перебора (или в нем, не знаю даже) Код (PHP): foreach($tree as $row) { print '<div style="padding-left:' . ($row['level']*20) . 'px;">' . $nodes[$row['id']]['txt'] . '</a></div>'; } получить вот массив? такой структуры? Код (Text): Array ( [0] => Array ( [id] => 4 [pid] => 0 [level] => 0 [text] => rrrr ) [1] => Array ( [id] => 5 [pid] => 4 [level] => 1 [text] => ssss ) [2] => Array ( [id] => 7 [pid] => 5 [level] => 2 [text] => gggggggg ) [3] => Array ( [id] => 8 [pid] => 0 [level] => 0 [text] =>fff ) ) Я как не пытался, у меня после перебора выходит последнее значение [3] => Array..... и все тут... Да, необходимо это, что бы не переписывать остальной скрипт, а переделать одну функцию, которая возвращает именно такой массив..... Ну если нет, то будем переделывать... Ну...у меня почти получилось.... Код (PHP): foreach($tree as $row) { // print '<div style="padding-left:' . ($row['level']*40) . 'px;">' . $nodes[$row['id']]['txt'] . $nodes[$row['id']]['author'].'</div>'; $items[] = $nodes[$row['id']]; } return $items но в итоге получается массив который мне нужен, но в нем нет $row['level'] точнее он есть, но тот который я писал раньше в БД, а оказывается действие это лишнее, и Ваш код прекрасно справляется и без этой записи в БД.... Подскажите как $row['level'] добавить в получаемый массив? Заранее благодарен!!!
*высоко подпрыгивает* УРА!!!!!!!! Код (PHP): foreach($tree as $row) { $nodes[$row['id']]['level'] = $row['level']; $items[] = $nodes[$row['id']]; } return $items; asokol еще раз спасибо за помощь! Возьмите меня в ученики, я быстро обучаюсь...