Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: Как упорядочить и отобразить иерархическую древовидную структуру?
Форумы портала PHP.SU » » Вопросы новичков » Как упорядочить и отобразить иерархическую древовидную структуру?

Страниц (1): [1]
 

1. РоманРоманыч - 20 Декабря, 2011 - 06:15:17 - перейти к сообщению
Парни, пожалуйста помогите разобраться, появилась такая задача:
есть исходный массив примерно такого содержания :

PHP:
скопировать код в буфер обмена
  1. 11111 => 0
  2. 22222 => 0
  3. 33333 => 0
  4. 44444 => 22222
  5. 55555 => 33333
  6. 66666 => 33333
  7. 77777 => 55555
  8. 88888 => 77777


как с помощью php упорядочить этот массив для вывода на страницу, что бы получилось именно так :
CODE (html):
скопировать код в буфер обмена
  1.  
  2. <div>
  3. 11111
  4. </div>
  5.  
  6. <div>
  7. 22222
  8.  <div>
  9.  44444
  10.  </div>
  11. </div>
  12.  
  13. <div>
  14. 33333
  15.  <div>
  16.  55555
  17.    <div>
  18.    77777
  19.      <div>
  20.      88888
  21.      </div>
  22.    </div>
  23.  </div>
  24.  <div>
  25.  11111
  26.  </div>
  27.  <div>
  28.  66666
  29.  </div>
  30. </div>
  31.  
  32.  

что бы элемент массива стал дочерним другого элемента, если его значение совпадает с ключем этого элемента. Элементы массива со значением 0 должны быть корневыми в итоговом дереве.
для наглядности :
┣11111
┣22222
┃ ┗44444
┣33333
┃ ┣55555
┃ ┃ ┗77777
┃ ┃ ┗88888
┃ ┗66666

...
понимаю, что нужна рекурсивная функция, но как ее правильно составить не могу понять. в этом примере только 3 уровня(или 4), на самом деле размер массива намного больше и вложения глубже, до 20 уровней.
Подскажите хотя бы в какую сторону копать, буду очень благодарен если решение все таки найдется! Однако
2. Самогонщик - 20 Декабря, 2011 - 06:29:51 - перейти к сообщению
Всё просто, первым делом строишь массив, в качестве ключа которого выступает родитель, а значения массив всех его потомков. (один цикл)

Далее пишешь функцию которая на вход принимает этот массив и ид элемента на вывод. В функции выводишь див, значение, в цикле вызываешь эту функцию для всех потомков (т.е. из массива по ключу ид), закрываешь див. Профит.

ну а первый вызов функции пишешь как цикл который вызывает функцию для всех значений в массиве под ключом нуль.
3. РоманРоманыч - 21 Декабря, 2011 - 03:36:14 - перейти к сообщению
Спасибо за подсказку, из гугла узнал, как выстороить многомерный массив в конструкцию с вложенными divами с помощью рекурсивной функции.
Самогонщик пишет:
Всё просто, первым делом строишь массив, в качестве ключа которого выступает родитель, а значения массив всех его потомков. (один цикл)

что только не курил не смог придумать нормального алгоритма по корректному конверту моего исходного одномерного массива в многомерный Однако
если кто сталкивался с подобным или знает решение этой задачки просьба чиркануть этот алгоритм, пойдет даже в грубом общем виде.

в исходном одномерном массиве ключ - потомок, его значение - родитель. Элементы с значением "0" - корневые.

пробовал так :
PHP:
скопировать код в буфер обмена
  1.                                                                                                                                                                                                
  2. $a=array('111'=>'0','222'=>'0','333'=>'0','444'=>'222','555'=>'333',
  3. '666'=>'333','777'=>'555','888'=>'777');
  4. $b=array();
  5.  
  6. foreach ($a as $k=>$v)
  7.   {
  8.    if($a[$k]=="0")
  9.    {                   
  10.    $c=array();
  11.    $b[$k]=$c;
  12.    }
  13.   }                                    
  14.  
  15.   echo '<pre>';
  16.   print_r($b); 
  17.   echo '</pre><hr>';   
  18.  
  19.   foreach ($a as $k=>$v)
  20.   {
  21.    if($v!="0")
  22.    {   
  23.    $c=array();
  24.    $c[$k]=array();
  25.    $b[$v]=$c;
  26.    }
  27.   }
  28.  
  29.   echo '<pre>';
  30.   print_r($b); 
  31.   echo '</pre><hr>';
  32.  
  33.  

получается не то что нужно Огорчение
4. Самогонщик - 21 Декабря, 2011 - 04:28:59 - перейти к сообщению
CODE (htmlphp):
скопировать код в буфер обмена
  1. $a=array('111'=>'0','222'=>'0','333'=>'0','444'=>'222','555'=>'333','666'=>'333','777'=>'555','888'=>'777');
  2. $b=array();
  3.  
  4. foreach ($a as $k=>$v)
  5. {
  6.   $b[$v][] = $k;
  7. }
  8.  
  9. print_r($b);

Кстати, подготовка исходного массива, резко повышает вероятность того, что сделают готовый пример.
5. РоманРоманыч - 21 Декабря, 2011 - 05:35:36 - перейти к сообщению
еще раз спасибо, очень близко к нужному, но к сожалению тоже не то.
в конечном виде должно получиться примерно так :
PHP:
скопировать код в буфер обмена
  1. (
  2.     [111] => Array
  3.         (
  4.         )
  5.  
  6.     [222] => Array
  7.         (
  8.             [0] => Array
  9.                 (
  10.                     [0] => 444
  11.                 )
  12.  
  13.         )
  14.  
  15.     [333] => Array
  16.         (
  17.             [0] => Array
  18.                 (
  19.                     [0] => Array
  20.                         (
  21.                             [0] => 777
  22.                             [1] => 888
  23.                         )
  24.  
  25.                 )
  26.  
  27.             [1] => 666
  28.         )
  29.  
  30. )

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

...| ID | PARENT_ID|...
----------------------------
...| 111|- |...
...| 222|- |...
...| 333|- |...
...| 444|222 |...
...
ну и так далее, как в исходном массиве, что я писал выше, где ID ид поста, PARENT_ID -
ид его родительского поста.
на странице должны быть видны только корневые посты, заключенные в специальные div-слайдеры с плюсиком, нажав на который, вопрос разварачивается и становятся видны все ответы, аналогично заключенные в блоки слайдеры, которые в свою очередь так же могут иметь некоторое количество ответов.
визуально это должно выглядеть примерно так :

вопрос №111 [-]
..(нет ответов)
вопрос №222 [-]
.. ответ №444 на вопрос №222 [-]
вопрос №333
.. ответ №555 на вопрос №333 [-]
.... ответ №777 на вопрос №555 [-]
.... ответ №888 на вопрос №555 [-]
.. ответ №666 на вопрос №333 [-]
...
...
...
нажимая на [-] он изменяется на [+] и все зависимые посты при этом сворачиваются, не тратя внимание пользователя на то что ему не нужно. вот такая задача.. Растерялся
6. Самогонщик - 21 Декабря, 2011 - 06:07:15 - перейти к сообщению
РоманРоманыч пишет:
в конечном виде должно получиться примерно так :
Ещё одним циклом можно получить и такое, но зачем?

Вот полный работающий пример, написанный согласно описанию в моём первом посте.
PHP:
скопировать код в буфер обмена
  1. $a=array('111'=>'0','222'=>'0','333'=>'0','444'=>'222','555'=>'333','666'=>'333','777'=>'555','888'=>'777');
  2. $b=array();
  3.  
  4. foreach ($a as $k=>$v)
  5.   $b[$v][] = $k;
  6.  
  7.  
  8. if($b['0'])
  9.   foreach($b['0'] as $child)
  10.     out_rec($b, $child);
  11.  
  12. function out_rec($dic, $curr)
  13. {
  14.   echo "<div>\n";
  15.   echo $curr,"\n";
  16.   if($dic[$curr])
  17.     foreach($dic[$curr] as $child)
  18.       out_rec($dic, $child);
  19.  
  20.   echo "</div>\n";  
  21. }

Как видно, такого подготовленного массива вполне достаточно для вывода дерева.

Хотя все эти подготовки - это муть, можно и без них
PHP:
скопировать код в буфер обмена
  1. $a=array('111'=>'0','222'=>'0','333'=>'0','444'=>'222','555'=>'333','666'=>'333','777'=>'555','888'=>'777');
  2.  
  3. foreach($a as $k=>$v)
  4.   if($v=='0')
  5.     out_rec($a, $k);
  6.  
  7. function out_rec($dic, $curr)
  8. {
  9.   echo "<div>\n";
  10.   echo $curr,"\n";
  11.   foreach ($dic as $k=>$v)
  12.     if($v == $curr)
  13.       out_rec($dic, $k);
  14.  
  15.   echo "</div>\n";  
  16. }


Вот только сложность будет о(Н2) вместо о(Н)
7. РоманРоманыч - 22 Декабря, 2011 - 12:41:33 - перейти к сообщению
Абсолютно то что надо! Код - прямо в десятку! Улыбка
БОЛЬШОЕ человеческое спасибище, Самогонщик! Крепко жму руку!
я не знал что такие приемы использования допустимы, да и опыта маловато.
еще раз спасибо все работает как надо! Здорово

 

Powered by ExBB FM 1.0 RC1