2010-12-01 12 views
6

ich einen Baum von Kategorien der folgenden Struktur:Rekursion und vorbei Referenz

[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 
          (
          ) 
        ) 
      ) 
    ) 

Neben einer Unterkategorie kann jede Kategorie Produkte enthält (wie ein Ordner Unterordner und nur Dateien enthält).

Ich versuche, eine rekursive Funktion zu schreiben, die ich dieses Array als Referenz nehmen und beide Blattkategorien mit [productCount] = 0 und alle übergeordneten Kategorien entfernen möchte, die solche leere Knoten enthalten. Mit anderen Worten, nach der Verarbeitung möchte ich nur die Kategorien haben, die Produkte auf beliebigen Unterebenen enthalten.

Ich habe etwas Code geschrieben, jetzt debuggen es und es leere Knoten nicht entfernt. Vielleicht verwende ich Referenzen nicht richtig. Bitte hilf mir, es zu beheben, wenn möglich.

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

Ist 'array() == false'? – jantimon

+1

@Ghommey: Ja, in PHP wird ein leeres Array als falsch angesehen. – BoltClock

Antwort

4

Sie können auch die Parameter in der Funktion ändern, um eine Reihe von Knoten anstelle eines einzelnen Knotens zu nehmen. Dadurch ändert sich die Rekursion leicht und verhindert die Notwendigkeit, an einen Schlüssel zu übergeben:

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]); 
      } 
     } 
    } 
} 

Auch eine Überprüfung hinzugefügt, dass, wenn alle Kinder gewährleistet Knoten zurückgeschnitten werden, die Eltern (jetzt, Blatt) Knoten wird auch beschnitten.

Hoffe, das hilft!


Testdaten:

$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() 
      ) 
     ) 
    ) 
); 

Der Call:

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

Es stellt sich heraus, dass es unmöglich ist, 'unset ($ nodes [$ key]);' innerhalb einer Funktion zu verwenden, um initiales Array zu ändern, das als Referenz übergeben wird, weil es die Referenzvariable innerhalb des Funktionsumfangs aufheben wird. – sevenWonders

+0

@sevenWonders - Ich habe vergessen zu erwähnen, dass ich dieses Skript (sowie Gumbo's) getestet habe und beide funktionieren. Es gibt praktisch keinen Unterschied, außer dass ich den Schlüssel innerhalb der aufgerufenen Funktion vor dem Unscharfstellen finde. – RabidFire

+0

@RabidFire - Seltsamerweise, wenn ich Ihre Funktion teste, erhalte ich einen Fehler "Nur Variablen können durch Referenz weitergegeben werden" in der Zeile 'pruneTree ($ nodes [$ key] ['children']);'. – sevenWonders

5

unset löscht nur die Referenz, aber nicht die referenzierten Variable:

Wenn eine Variable, die als Referenz übergeben wird unset() innerhalb einer Funktion ist, wird nur die lokale Variable zerstört wird. Die Variable in der aufrufenden Umgebung behält den gleichen Wert wie zuvor unset() wurde aufgerufen.

So müssen Sie das übergeordnete Array und den Schlüssel zu übergeben diese Variable löschen:

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

Danke, Gumbo! Ich habe auf der "references" -Seite des Handbuchs nach Hinweisen gesucht und den Punkt mit "unset" und dem Scope verpasst. – sevenWonders

0

Ich weiß nicht, ob dies der Fall ist, aber wenn ich benötigten Werte rekursiv in Array ändern , ich musste & zum foreach Wert auch führen.

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); 
      } 
     } 
    }