2010-12-01 17 views
6

Mam drzewo kategorii następującej strukturze:Recursion i przechodzącej przez odniesienie

[6] => Array 
    (
     [id] => 6 
     [name] => computers 
     [productCount] => 0 
     [children] => Array 
      (
       [91] => Array 
        (
         [id] => 91 
         [name] => notebook 
         [productCount] => 5 
         [children] => Array 
          (
          ) 
        ) 

       [86] => Array 
        (
         [id] => 86 
         [name] => desktop 
         [productCount] => 0 
         [children] => Array 
          (
          ) 
        ) 
      ) 
    ) 

obok podkategorii, każda kategoria może zawierać produkty (jak folder może zawierać podfoldery i pliki tylko).

Próbuję napisać funkcję rekurencyjną, którą chcę wziąć tę tablicę jako odniesienie i rozrysować obie kategorie liści za pomocą [productCount] = 0 i wszystkich kategorii nadrzędnych, które zawierają takie puste węzły. Innymi słowy, po przetworzeniu chcę mieć tylko te kategorie, które przechowują produkty na dowolnych podpoziomach.

Napisałem trochę kodu, teraz debuguję go i nie usuwa on pustych węzłów. Być może nie używam referencji poprawnie. Proszę, pomóż mi to naprawić, jeśli to możliwe.

function pruneTree(& $node) { 
    if (! $node['children'] && ! $node['productCount']) { 
     unset($node); 
    } 
    if (! empty($node['children'])) { 
     foreach ($node['children'] as $key => $child) { 
      pruneTree($node['children'][$key]); 
     } 
    } 
    return; 
} 
+0

Czy 'tablica() == fałsz'? – jantimon

+1

@Ghommey: Tak, w PHP pusta tablica jest uważana za falsy. – BoltClock

Odpowiedz

4

Można także zmienić parametr w funkcji wziąć tablicę węzłów zamiast pojedynczego węzła. To zmienia rekursji lekko i zapobiega konieczności przechodzenia wzdłuż klucza:

function pruneTree(&$nodes) { 
    foreach ($nodes as $key => $node) { 
     if (!$node['children'] && !$node['productCount']) { 
      unset($nodes[$key]); 
     } elseif (!empty($node['children'])) { 
      pruneTree($nodes[$key]['children']); 
      // This line checks if all the children have been pruned away: 
      if (empty($nodes[$key]['children'])) { 
       unset($nodes[$key]); 
      } 
     } 
    } 
} 

Również dodaje czek, który zapewnia, że ​​jeśli wszystkie węzły potomne są przycinane, rodzic (obecnie, liść) węzeł również zostaje przycinany.

Mam nadzieję, że to pomoże! Dane


Test:

$data = array(
    6 => array(
     'id' => 6, 
     'name' => 'computers', 
     'productCount' => 0, 
     'children' => array(
      91 => array(
       'id' => 91, 
       'name' => 'notebook', 
       'productCount' => 5, 
       'children' => array() 
      ), 
      86 => array(
       'id' => 86, 
       'name' => 'desktop', 
       'productCount' => 0, 
       'children' => array() 
      ) 
     ) 
    ) 
); 

Call:

pruneTree($data); 
echo '<pre>'; 
print_r($data); 
echo '</pre>'; 
+0

Okazuje się, że niemożliwe jest użycie 'unset ($ nodes [$ key]);' wewnątrz funkcji do modyfikacji początkowej tablicy, która jest przekazywana przez odniesienie, ponieważ po prostu odłączy zmienną referencyjną w zakresie funkcji. – sevenWonders

+0

@sevenWonders - Zapomniałem wspomnieć, że przetestowałem ten skrypt (tak samo jak Gumbo) i oba działają. Nie ma praktycznie żadnej różnicy, z wyjątkiem tego, że znajduję klucz od wewnątrz wywoływanej funkcji przed wyłączeniem. – RabidFire

+0

@RabidFire - Dziwnie kiedy testuję twoją funkcję, pojawia się błąd "Tylko zmienne mogą być przekazywane przez odniesienie" w linii 'pruneTree ($ węzłów [$ key] ['children']);'. – sevenWonders

5

unset usuwa jedynie odniesienie, ale nie odwołuje zmienną:

Jeśli zmienna jest przekazywane przez referencję jest unset() wewnątrz funkcji, tylko zmienna lokalna jest zniszczona. Zmienna w środowisku wywołującym zachowa taką samą wartość, jak przed wywołaniem unset().

Więc trzeba przekazać tablicę nadrzędną i klawisz, aby usunąć tę zmienną:

function pruneTree(&$parent, $key) { 
    $node = &$parent[$key]; 
    if (!$node['children'] && !$node['productCount']) { 
     unset($parent[$key]); 
    } 
    if (!empty($node['children'])) { 
     foreach ($node['children'] as $key => &$child) { 
      pruneTree($node['children'], $key); 
     } 
    } 
} 
+0

Dziękuję, Gumbo! Szukałem wskazówek na stronie "referencje" podręcznika i nie trafiłem w punkt z "unset" i zakresem. – sevenWonders

0

nie wiem, czy jest to przypadek, ale kiedy potrzebne do rekursywnie zmienić wartości w tablicy , musiałem również przekazać & do wartości foreach.

private function convertXMLPart(&$array) { 
     foreach ($array as $rowKey => &$row) { 
      if (gettype($row) != 'string') { 
       $row = (array)$row; 
       if (!empty($row['@attributes'])) { 
        foreach ($row['@attributes'] as $key => $value) { 
         $row[$key] = $value; 
        } 
        unset($row['@attributes']); 
        $array[$rowKey] = $row; 
       } 
       $this->convertXMLPart($row); 
      } 
     } 
    } 
Powiązane problemy