За последние 24 часа нас посетили 22076 программистов и 1682 робота. Сейчас ищут 1737 программистов ...

Посчитать "уровень вложенности многомерного массива"

Тема в разделе "Вопросы от блондинок", создана пользователем Dmitriy A. Arteshuk, 19 янв 2012.

  1. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    придумал! пусть тот член называется igordata потянет? :)

    НЛ, если что :)
     
  2. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    да хоть сюзанна.
     
  3. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    обиделся чтоль? :(
     
  4. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    Код (Text):
    1.  
    2.  
    3. $array = array(
    4.     0 => array(
    5.         'id' => 15,
    6.         'pid' => 0,
    7.         'module_id' => 1,
    8.         'igordata' => array(
    9.             0 => array(
    10.                 'id' => 16,
    11.                 'pid' => 15,
    12.                 'module_id' => 'comments1'
    13.             ),
    14.             1 => array(
    15.                 'id' => 21,
    16.                 'pid' => 16,
    17.                 'module_id' => 'comments1'
    18.             )
    19.         )
    20.     )
    21. );
    22.  
    23. function recur($what, $where, $level = 0) {
    24.   $level++;
    25.   foreach ($where as $entry) {
    26.     if (isset($entry['id']) AND $entry['id'] == $what) {
    27.       return $level;
    28.     } else {
    29.       if (isset($entry['igordata'])) {
    30.         return recur($what, $entry['igordata'], $level);
    31.       }
    32.     }
    33.   }
    34.   return false;
    35. }
    36.  
    37. var_dump(recur(21, $array));
     
  5. asokol

    asokol Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    162
    Симпатии:
    0
    [vs],
    Код (Text):
    1.  
    2. $v = current($array);
    3. while (is_array($v)) {
    4.      $level++;
    5.      $v = current($array);
    6. }
    Ваш пример считает до бесконечности. А точнее, до превышения ограничения по времени.
    В том виде, как его подправил топикстартер, он действительно считает то, что нужно.

    Дмитрий, код [vs], который Вы поправили, все правильно считает. У id21 предок id16, а не id15, поэтому и получается 1, 2, 3.
     
  6. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    igordata спасибо за код, но...я в самом первом посте написал: ну вобщем любой элемент, ибо функция должна быть универсальной, вычислять любой уровень вложенности... если бы задача стояла вычислить какой то конкретные массив, "руками" бы перебрал да вычислил :)
    asokol к сожалению не правильно она считает, привожу еще раз код:

    Имеем массив:

    Код (Text):
    1. Array
    2. (
    3.     [0] => Array
    4.         (
    5.             [id] => 15
    6.             [pid] => 0
    7.             [nodes] => Array
    8.                 (
    9.                     [0] => Array
    10.                         (
    11.                             [id] => 32
    12.                             [pid] => 15
    13.                         )
    14.  
    15.                     [1] => Array
    16.                         (
    17.                             [id] => 16
    18.                             [pid] => 15
    19.                             [nodes] => Array
    20.                                 (
    21.                                     [0] => Array
    22.                                         (
    23.                                             [id] => 30
    24.                                             [pid] => 16
    25.                                             [nodes] => Array
    26.                                                 (
    27.                                                     [0] => Array
    28.                                                         (
    29.                                                             [id] => 31
    30.                                                             [pid] => 30
    31.                                                         )
    32.                                                 )
    33.                                         )
    34.                                 )
    35.                         )
    36.                 )
    37.         )
    38. )
    далее пытаемся считать:

    Код (Text):
    1.  
    2.         $tree = array();
    3.         $nodes = array();
    4.         $keys = array();
    5.            
    6.         while ($row = mysql_fetch_assoc($result))
    7.         {
    8.             $nodes[$row['id']] =& $row; //заполняем список веток записями из БД
    9.             $keys[] = $row['id']; //заполняем список ключей(ID)
    10.             unset($row);
    11.         }
    12.        
    13.         $level = 0;
    14.  foreach ($keys as $key)
    15.  {
    16. // если нашли главную ветку(или одну из главных), то добавляем  её в дерево    
    17.         if ($nodes[$key]['pid'] === '0')
    18.             $tree[] =& $nodes[$key];
    19. // else находим родительскую ветку и добавляем текущую ветку к дочерним элементам родит.ветки.
    20.         else
    21.         {
    22.             if (isset($nodes[ $nodes[$key]['pid'] ])) //на всякий случай, вдруг в базе есть потерянные ветки
    23.             {
    24.                 if (! isset($nodes[ $nodes[$key]['pid'] ]['nodes'])) //если нет поля определяющего наличие дочерних веток
    25.                 $nodes[ $nodes[$key]['pid'] ]['nodes'] = array(); //то добавляем к записи узел (массив дочерних веток) на данном этапе
    26.                
    27.                 $nodes[ $nodes[$key]['pid'] ]['nodes'][] =& $nodes[$key];
    28.             }
    29.         }
    30.  
    31.     $v = current($nodes);
    32.     while (is_array($v))
    33.         {
    34.         $level++;
    35.         $v = current($v);
    36.         echo $level."|<br>";
    37.        }
    38. }
    на выходе в $level имеем:
    Код (Text):
    1.  
    2. 1|
    3. 2|
    4. 3|
    5. 4|
    6. 5|
    а надо что бы получилось

    Код (Text):
    1.  
    2. 1|
    3. 2|
    4. 2|
    5. 3|
    6. 4|
    что я делаю не так? (ну понятно что все и надо идти читать мануалы...но все же?)
     
  7. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Возможно дело в том, что в $level сохраняется значение от подсчета прошлой ветки.
     
  8. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    и как быть?
     
  9. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    ой, да... =) ну начало положено, осталось сделать пару строк.
     
  10. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    давай Гарик, твой выход! :)
     
  11. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    я уже не могу сегодня. могу только флудить.
     
  12. asokol

    asokol Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    162
    Симпатии:
    0
    $level = 0 внести внутрь foreach.
    Через минут 15 посмотрю код, в чем может быть проблема.
     
  13. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    внес

    Код (Text):
    1. foreach ($keys as $key)
    2.     {
    3. $level = 0;
    на выходе
    Код (Text):
    1. 1|
    2. 1|
    3. 1|
    4. 1|
    5. 1|
    я вот думаю, а может проще

    Код (Text):
    1.  
    2.         while ($row = mysql_fetch_assoc($result))
    3.         {;
    4.             $items[] = $row;;
    5.         }
    6.  
    7. // это $items
    8. Array
    9. (
    10.     [0] => Array
    11.         (
    12.             [id] => 15
    13.             [pid] => 0
    14.         )
    15.  
    16.     [1] => Array
    17.         (
    18.             [id] => 16
    19.             [pid] => 15
    20.         )
    21.  
    22.     [2] => Array
    23.         (
    24.             [id] => 30
    25.             [pid] => 16
    26.         )
    27.  
    28.     [3] => Array
    29.         (
    30.             [id] => 31
    31.             [pid] => 30
    32.         )
    33.  
    34.     [4] => Array
    35.         (
    36.             [id] => 32
    37.             [pid] => 15
    38.         )
    39. )
    и как-то по pid считать....но боюсь это даже говнокодней чем я до этого написал )))

    Что-то мне подсказывает, что должно быть какое-то очень простое решение как получить из БД дерево имея id и parent_id.....
     
  14. asokol

    asokol Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    162
    Симпатии:
    0
    Да, вы правы, код [vs] не делает того, что нужно.

    Я посмотрел Ваш код, вот он (в том виде, в котором мне проще):
    Код (Text):
    1.  
    2. $tree = array();
    3. $nodes = array();
    4. $keys = array();
    5.  
    6. while ($row = mysql_fetch_assoc($result)) {
    7.     $nodes[$row['id']] =& $row; //заполняем список веток записями из БД
    8.     $keys[] = $row['id']; //заполняем список ключей(ID)
    9.     unset($row);
    10. }
    11.  
    12. foreach($keys as $key) {
    13.     // если нашли главную ветку(или одну из главных), то добавляем  её в дерево    
    14.     if ($nodes[$key]['pid'] === '0') $tree[] =& $nodes[$key];
    15.     else { // else находим родительскую ветку и добавляем текущую ветку к дочерним элементам родит.ветки.
    16.         if (isset($nodes[ $nodes[$key]['pid'] ])) { // на всякий случай, вдруг в базе есть потерянные ветки
    17.             // если нет поля определяющего наличие дочерних веток
    18.             // то добавляем к записи узел (массив дочерних веток) на данном этапе
    19.             if (!isset($nodes[ $nodes[$key]['pid'] ]['nodes'])) $nodes[ $nodes[$key]['pid'] ]['nodes'] = array();
    20.             $nodes[ $nodes[$key]['pid'] ]['nodes'][] =& $nodes[$key];
    21.         }
    22.     }
    23. }
    Если я правильно понимаю ситуацию, то надо посчитать вложенность для того, чтобы потом при выводе правильно разместить комментарии относительно их родителей. Если это так, то я не вижу смысла считать $level вообще. Лучше это сделать на этапе вывода. Потому что для вывода все равно придется пройтись по всем элементам.
     
  15. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    если не сложно, в общих чертах не подскажите как?

    я вот еще подумал, а может все же на этапе ввода?

    <input type="hidden" id="level" name="level" value="%level%" />

    первый комент: pid =0, level=0. дочкам этого комента при занесении в базу, плюсуем 1 к level...

    или неверный путь? (в любом случае сейчас попробую)

    попробовал, все чудненько, остался только один вопрос:

    как сделать так, что бы вот это


    Код (Text):
    1. $tree = array();
    2. $nodes = array();
    3. $keys = array();
    4.  
    5. while ($row = mysql_fetch_assoc($result)) {
    6.     $nodes[$row['id']] =& $row; //заполняем список веток записями из БД
    7.     $keys[] = $row['id']; //заполняем список ключей(ID)
    8.     unset($row);
    9. }
    10.  
    11. $level = 0;  
    12. foreach($keys as $key) {
    13.     // если нашли главную ветку(или одну из главных), то добавляем  её в дерево    
    14.     if ($nodes[$key]['pid'] === '0') $tree[] =& $nodes[$key];
    15.     else { // else находим родительскую ветку и добавляем текущую ветку к дочерним элементам родит.ветки.
    16.         if (isset($nodes[ $nodes[$key]['pid'] ])) { // на всякий случай, вдруг в базе есть потерянные ветки
    17.             // если нет поля определяющего наличие дочерних веток
    18.             // то добавляем к записи узел (массив дочерних веток) на данном этапе
    19.             if (!isset($nodes[ $nodes[$key]['pid'] ]['nodes'])) $nodes[ $nodes[$key]['pid'] ]['nodes'] = array();
    20.             $nodes[ $nodes[$key]['pid'] ]['nodes'][] =& $nodes[$key];
    21.         }
    22.     }
    23. }
    на выходе давало мне одномерный массив? Но ОБЯЗАТЕЛЬНО в том же порядке, в котором выводит сейчас
     
  16. asokol

    asokol Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    162
    Симпатии:
    0
    Это для того, чтобы вывести было проще?
    $level = 0; - можно убрать.
     
  17. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    мдя...ларчик то просто открывался :) говорила мне мама, не слушай шибко умных и флудных даденек :)

    и так:

    при записи нового коммента в БД мы записывает level , равный +1 к имеющемуся. Если в корень коммент пишем ноль.

    далее выборка и обработка

    Код (Text):
    1.         $tree = array();
    2.         $nodes = array();
    3.         $keys = array();
    4.            
    5.         while ($row = mysql_fetch_assoc($result))
    6.         {      
    7.             $nodes[$row['id']] =& $row;
    8.             $keys[] = $row['id'];
    9.             unset($row);
    10.         }
    11.    
    12.     foreach ($keys as $key)
    13.     {
    14.             $tree[] =& $nodes[$key];
    15.     }
    16.  
    17. return $tree;
    в итоге на выходе одномерный массив в том порядке, в котором нам необходимо (хотя в этом у меня пока сомнения)

    ну а там уже по level делаем отступы.....

    ВСЕ ПОЛУЧИЛОСЬ, СПАСИБО!!!!

    а то рекурсия рекурсия ))))
     
  18. asokol

    asokol Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    162
    Симпатии:
    0
    Что ж, дело Ваше. Не слушайте больше.

    К сожалению, это неверное решение.
    Удачи.
     
  19. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    я предполагал что это так, подскажите пожалуйста верное, если не сложно....

    все же при выводу делать сортировку?
     
  20. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    WTF, зачем здесь &?
    Для дерева надо простой цикл из моего примера заменить функцией, которую вызывать внутри её же до тех пор, пока не пройдет перебор всего дерева.
    Вот пример как делать рекурсию с помощью функции.
    Код (PHP):
    1. $arr = array(1,1,1,1,array(1,1,1,array(1,1),1,1,array(1,1,1),1));
    2. function dub_arr($arr) {
    3.      foreach ($arr as &$v) {
    4.           $v = is_array($v) ? dub_arr($v) : $v * 2;
    5.      }
    6.      return $arr;
    7. }
    8. print_r(dub_arr($arr)); 
     
  21. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    признаю, путь не верный, выводит хрен знает как, не могу отсортировать как положено.... :(
     
  22. asokol

    asokol Активный пользователь

    С нами с:
    17 янв 2012
    Сообщения:
    162
    Симпатии:
    0
    Код (PHP):
    1. $nodes = $pids = array();
    2. // новые в конце
    3. $result = mysql_query("SELECT `id`, `pid`, `text` FROM `table` ORDER BY `id` ASC;");
    4. while ($row = mysql_fetch_assoc($result)) {
    5.     if (!isset($pids[$row['pid']])) $pids[$row['pid']] = array();
    6.     $pids[$row['pid']][] = $row['id'];
    7.     $nodes[$row['id']] = $row;
    8. }
    9. unset($row);
    10. // раскомментировать, чтобы новые были в начале
    11. //$pids[0] = array_reverse($pids[0]);
    12. $tree = get_nodes($pids, 0);
    13. unset($pids);
    14. foreach($tree as $row) {
    15.     print '<div style="padding-left:' . ($row['level']*20) . 'px;">' . $nodes[$row['id']]['text'] . '</a></div>';
    16. }
    17.  
    18. function get_nodes(&$pids, $pid, $level = 0) {
    19.     foreach($pids[$pid] as $id) {
    20.         $tree[] = array('id' => $id, 'level' => $level);
    21.         if (!empty($pids[$id])) $tree = array_merge($tree, get_nodes($pids, $id, $level+1));
    22.     }
    23.     return $tree;
    24. }
    25.  
     
  23. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    asokol - гениально! Огромное спасибо за помощь!
     
  24. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    asokol моя благодарность не знает границ, но осмелюсь попросить еще :(

    подскажите, возможно ли как-то, на выходе, после перебора (или в нем, не знаю даже)

    Код (PHP):
    1. foreach($tree as $row) {
    2.     print '<div style="padding-left:' . ($row['level']*20) . 'px;">' . $nodes[$row['id']]['txt'] . '</a></div>';
    3. } 
    получить вот массив? такой структуры?

    Код (Text):
    1. Array
    2. (
    3.     [0] => Array
    4.         (
    5.             [id] => 4
    6.             [pid] => 0
    7.             [level] => 0
    8.             [text] => rrrr
    9.         )
    10.  
    11.     [1] => Array
    12.         (
    13.             [id] => 5
    14.             [pid] => 4
    15.             [level] => 1
    16.             [text] => ssss
    17.         )
    18.  
    19.     [2] => Array
    20.         (
    21.             [id] => 7
    22.             [pid] => 5
    23.             [level] => 2
    24.             [text] => gggggggg
    25.         )
    26.  
    27.     [3] => Array
    28.         (
    29.             [id] => 8
    30.             [pid] => 0
    31.             [level] => 0
    32.             [text] =>fff
    33.         )
    34. )
    Я как не пытался, у меня после перебора выходит последнее значение [3] => Array..... и все тут...

    Да, необходимо это, что бы не переписывать остальной скрипт, а переделать одну функцию, которая возвращает именно такой массив.....
    Ну если нет, то будем переделывать...

    Ну...у меня почти получилось....

    Код (PHP):
    1. foreach($tree as $row) {
    2. //    print '<div style="padding-left:' . ($row['level']*40) . 'px;">' . $nodes[$row['id']]['txt'] . $nodes[$row['id']]['author'].'</div>';
    3.     
    4.     $items[] = $nodes[$row['id']]; 
    5. }
    6. return $items
    но в итоге получается массив который мне нужен, но в нем нет $row['level'] :(
    точнее он есть, но тот который я писал раньше в БД, а оказывается действие это лишнее, и Ваш код прекрасно справляется и без этой записи в БД....

    Подскажите как $row['level'] добавить в получаемый массив?
    Заранее благодарен!!!
     
  25. Dmitriy A. Arteshuk

    Dmitriy A. Arteshuk Активный пользователь

    С нами с:
    19 янв 2012
    Сообщения:
    2.445
    Симпатии:
    66
    Адрес:
    Зеленоград
    *высоко подпрыгивает* УРА!!!!!!!!

    Код (PHP):
    1. foreach($tree as $row) {
    2.     $nodes[$row['id']]['level'] = $row['level'];
    3.     $items[] = $nodes[$row['id']]; 
    4. }
    5.  
    6. return $items; 
    asokol еще раз спасибо за помощь!

    Возьмите меня в ученики, я быстро обучаюсь...