Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP] Plaska struktura tablic do drzewa
Forum PHP.pl > Forum > Przedszkole
Mastobol
Z bazy danych wyciagam po kolei rekordy i wrzucam je do tablicy asocjacyjnej tworzac plaska strukture. Obiekty sa node'ami w relacji parent->child z wieloma poziomami zagniezdenia. Przykladowa struktura posortowana po id wyglada tak :

  1. (
  2. [22] => Array
  3. (
  4. [Id] => 22
  5. [parentId] => 14
  6. [Name] => T2
  7. )
  8.  
  9. [14] => Array
  10. (
  11. [Id] => 14
  12. [parentId] => null
  13. [Name] => T1
  14. )
  15.  
  16. [43] => Array
  17. (
  18. [Id] => 43
  19. [parentId] => 22
  20. [Name] => T2 child
  21. )
  22.  
  23. [42] => Array
  24. (
  25. [Id] => 42
  26. [parentId] => 14
  27. [leaf] => true
  28. )
  29.  
  30. [41] => Array
  31. (
  32. [Id] => 41
  33. [parentId] => null
  34. [Name] => T4
  35. )
  36.  
  37. [40] => Array
  38. (
  39. [Id] => 40
  40. [parentId] => null
  41. [Name] => T5
  42. )
  43. )


Parametr parentId wskazuje na rodzica wezla. Wartosc null oznacza,ze wezel jest pierwszym poziomem i bedzie dzieckiem root'a (ktory jest tworzony gdzie indziej i tutaj nigdy sie nie pojawi). I teraz pytanie. Jak zamienic to na drzewiasta strukture, gdzie dzieci wezla znajda sie w tablicy children ? :

  1. [0] => Array
  2. (
  3. [Id] => 14
  4. [parentId] => null
  5. [Name] => T1
  6. [children] => Array
  7. (
  8. [0] => Array
  9. (
  10. [Id] => 22
  11. [parentId] => 14
  12. [Name] => T2
  13. [children] => Array
  14. (
  15. [0] => Array
  16. (
  17. [Id] => 43
  18. [parentId] => 22
  19. [Name] => T2 child
  20. )
  21.  
  22. )
  23.  
  24. )
  25. )
  26. )


Walcze z tym juz troche czasu i jak dotad ine udalo mi sie wykombinowac nic co bedzie dzialalo w kazdym przypadku. Znalazlem cos takiego :

  1. $arr = array(
  2. array('id'=>100, 'parentid'=>0, 'name'=>'a'),
  3. array('id'=>101, 'parentid'=>100, 'name'=>'a'),
  4. array('id'=>102, 'parentid'=>101, 'name'=>'a'),
  5. array('id'=>103, 'parentid'=>101, 'name'=>'a'),
  6. );
  7.  
  8. $new = array();
  9. foreach ($arr as $a){
  10. $new[$a['parentid']][] = $a;
  11. }
  12. $tree = createTree($new, $new[0]);
  13. print_r($tree);
  14.  
  15. function createTree(&$list, $parent){
  16. $tree = array();
  17. foreach ($parent as $k=>$l){
  18. if(isset($list[$l['id']])){
  19. $l['children'] = createTree($list, $list[$l['id']]);
  20. }
  21. $tree[] = $l;
  22. }
  23. return $tree;
  24. }


Ale w tym rozwiazaniu trzeba podac id pierwszego poziomu ($new[0], ktore u mnie jest null) a calosc mimo wszystko nie buduje poprawnej struktury. Z gory dziekuje za wszelka pomoc bo pehapowiec ze mnie zaden i normalnie zajmuje sie frontendem ale w czasie wakacji roznie to bywa :/
darko
Musiałbyś napisać swój komparator i przekazać go do funkcji uasort zob. przykład 1. - funkcja cmp. Taki komparator układałby Ci dzieci w odpowiedniej pozycji dla odpowiedniego node'a (po kolei) i sklejałby z tego jedną tablicę z wieloma zagłębieniami. Nie jest to mega skomplikowane, a eleganckim rozwiązaniem mogłoby być użycie rekurencji.
Mastobol
Czyli po kolei, co ma robic ten komparator ? Leci sobie po tablicy i znajduje pierwszego node'a (zalozmy, ze ma id=2):

- powiedzmy,ze wezel ma parentId=1
- szukam w tablicy wezla z id=1 i mu wezel z id=2 w tablice children

Tylko,ze teraz jesli jakis inny wezel ma parentId=2 to jak mam znalezc ten wezel, ktory jest w tablicy children wezla 1 ? Moglbym prosic o jakis pseudokod ?
darko
Hej! To po kolei, bez rekurencji i bez komparatora, na szybko spróbuj czegoś takiego:
  1. echo '<pre>';
  2.  
  3. $arr = Array
  4. (
  5. '22' => Array
  6. (
  7. 'Id' => 22,
  8. 'parentId' => 14,
  9. 'Name' => 'T2'
  10. ),
  11.  
  12. '14' => Array
  13. (
  14. 'Id' => 14,
  15. 'parentId' => null,
  16. 'Name' => 'T1',
  17. ),
  18.  
  19. '43' => Array
  20. (
  21. 'Id' => 43,
  22. 'parentId' => 22,
  23. 'Name' => 'T2 child'
  24. ),
  25.  
  26. '42' => Array
  27. (
  28. 'Id' => 42,
  29. 'parentId' => 14,
  30. 'leaf' => true,
  31. ),
  32.  
  33. '41' => Array
  34. (
  35. 'Id' => 41,
  36. 'parentId' => null,
  37. 'Name' => 'T4'
  38. ),
  39.  
  40. '40' => Array
  41. (
  42. 'Id' => 40,
  43. 'parentId' => null,
  44. 'Name' => 'T5'
  45. )
  46. );
  47.  
  48. print_r($arr);
  49.  
  50. $sortedArray = array();
  51. // znajdź rodziców
  52. foreach($arr as $k => $v)
  53. {
  54. if(is_null($v['parentId']))
  55. {
  56. $sortedArray[$k] = $v;
  57. }
  58. }
  59. // sortuj rodziców
  60. asort($sortedArray);
  61.  
  62. function findChildren(array & $a1, array & $a2)
  63. {
  64. foreach($a1 as $k => $v)
  65. {
  66. if(!is_null($v['parentId']))
  67. {
  68. if(array_key_exists($v['parentId'], $a2))
  69. {
  70. $a2[$v['parentId']]['children'][$v['Id']] = $v;
  71. unset($a1[$k]);
  72. }
  73. }
  74. else
  75. {
  76. unset($a1[$k]);
  77. }
  78. }
  79.  
  80. foreach($a1 as $k => $v)
  81. {
  82. foreach($a2 as $x1 => $x2)
  83. {
  84. $temp = @$x2['children'];
  85. if(isset($temp))
  86. {
  87. if(array_key_exists($v['parentId'], $temp))
  88. {
  89. $a2[$x1]['children'][$v['parentId']]['children'][$v['Id']] = $v;
  90. unset($a1[$k]);
  91. }
  92. }
  93. }
  94. }
  95.  
  96. return $a2;
  97. }
  98.  
  99. echo findChildren($arr, $sortedArray);
  100.  
  101. echo '<hr/>';
  102. //print_r($arr);
  103. print_r($sortedArray);


######### wynik: #########
Kod
Array
(
    [22] => Array
        (
            [Id] => 22
            [parentId] => 14
            [Name] => T2
        )

    [14] => Array
        (
            [Id] => 14
            [parentId] =>
            [Name] => T1
        )

    [43] => Array
        (
            [Id] => 43
            [parentId] => 22
            [Name] => T2 child
        )

    [42] => Array
        (
            [Id] => 42
            [parentId] => 14
            [leaf] => 1
        )

    [41] => Array
        (
            [Id] => 41
            [parentId] =>
            [Name] => T4
        )

    [40] => Array
        (
            [Id] => 40
            [parentId] =>
            [Name] => T5
        )

)
Array
Array
(
    [14] => Array
        (
            [Id] => 14
            [parentId] =>
            [Name] => T1
            [children] => Array
                (
                    [22] => Array
                        (
                            [Id] => 22
                            [parentId] => 14
                            [Name] => T2
                            [children] => Array
                                (
                                    [43] => Array
                                        (
                                            [Id] => 43
                                            [parentId] => 22
                                            [Name] => T2 child
                                        )

                                )

                        )

                    [42] => Array
                        (
                            [Id] => 42
                            [parentId] => 14
                            [leaf] => 1
                        )

                )

        )

    [40] => Array
        (
            [Id] => 40
            [parentId] =>
            [Name] => T5
        )

    [41] => Array
        (
            [Id] => 41
            [parentId] =>
            [Name] => T4
        )

)


W takiej postaci łatwo to przerobić na rekurencję i obsłużyć nieskończenie wiele (do limitu zagnieżdżeń tablic - ustawienia php) zagłębień relacji rodzic-dziecko.

Zob. przykład 2
Mastobol
Wielkie dzieki za pomoc. Ostateczna wersja wyglada tak :

  1. $sortedArray = array();
  2. // get first level
  3. foreach($tasks as $k => $v){
  4. if($v['parentId'] == 'null'){
  5. $sortedArray[$k] = $v;
  6. unset($tasks[$k]);
  7. }
  8. }
  9.  
  10. function getChildren(array & $a1, array & $a2){
  11. foreach($a1 as $k => $v){
  12. findChildren($v, $a2, $k);
  13. }
  14. }
  15.  
  16. function findChildren($rec1, array & $a2, $key){
  17.  
  18. foreach($a2 as $k => $v){
  19. if($rec1['parentId'] == $v['Id']){
  20. $a2[$k]['children'][$rec1['Id']] = $rec1;
  21. unset($tasks[$key]);
  22. } else {
  23. if (isset($v['children'])){
  24. findChildren($rec1, $a2[$k]['children'], $key);
  25. }
  26. }
  27. }
  28. }
  29.  
  30. function makeIndexed(array & $arr, array & $par = null){
  31. if(is_null($par)){
  32. $arr = array_values($arr);
  33. } else {
  34. $par['children'] = array_values($arr);
  35. }
  36.  
  37. for($i=0; $i<count($arr); $i++) {
  38. $temp = @$arr[$i]['children'];
  39. if(isset($temp)) {
  40. makeIndexed($arr[$i]['children'], $arr[$i]);
  41. }
  42. }
  43. }
  44.  
  45. getChildren($tasks, $sortedArray);
  46.  
  47. makeIndexed($sortedArray);


Nie jest to ani najpiekniejszy ani najwydajniejszy kod php na tej planecie ale wydaje sie dzialac i jest szczytem moich obecnych mozliwosci smile.gif Funkcja 'makeIndexed' dodana dla stworzenia JSON'a, w ktorym dzieci sa tablicami obiektow a nie obiekiami.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.