2010-12-01 13 views
6

Ho un albero di categorie della seguente struttura:ricorsione e il passaggio per riferimento

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

Accanto a una sottocategoria, ogni categoria può contenere prodotti (come una cartella può contenere sottocartelle e solo i file).

Sto provando a scrivere una funzione ricorsiva che voglio prendere questo array come riferimento e rimuovere entrambe le categorie foglia con [productCount] = 0 e tutte le categorie padre che contengono tali nodi vuoti. In altre parole, dopo l'elaborazione voglio avere solo quelle categorie che contengono prodotti su qualsiasi sottolivello.

Ho scritto del codice, ora il debug e non elimina i nodi vuoti. Forse non sto usando i riferimenti correttamente. Per favore, aiutami a risolverlo, se possibile.

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

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

+1

@Ghommey: Sì, in PHP una matrice vuota è considerata falsa. – BoltClock

risposta

4

si potrebbe anche modificare il parametro nella funzione di prendere una serie di nodi, invece di un singolo nodo. Questo cambia la ricorsione un po ', e impedisce la necessità di passare lungo un tasto:

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

Inoltre, ha aggiunto un assegno che garantisce che, se tutti i nodi figlio vengono potate, il genitore (oggi, foglie) nodo anche viene potata.

Spero che questo aiuti! Dati


prova:

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

The Call:

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

Si scopre che è impossibile usare 'unset ($ nodes [$ key]);' all'interno di una funzione per modificare l'array iniziale che viene passato per riferimento, in quanto annulla semplicemente la variabile di riferimento all'interno dell'ambito delle funzioni. – sevenWonders

+0

@sevenWonders - Ho dimenticato di menzionare che ho testato questo script (oltre a quello di Gumbo) e funzionano entrambi. Non c'è praticamente alcuna differenza, tranne il fatto che trovo la chiave all'interno della funzione chiamata prima di disattivarla. – RabidFire

+0

@RabidFire - Stranamente quando provo la tua funzione ottengo un errore "Solo le variabili possono essere passate per riferimento" alla riga 'pruneTree ($ nodes [$ key] ['children']);'. – sevenWonders

5

unset elimina solo il riferimento, ma non la variabile di riferimento:

Se una variabile PASSATA PER RIFERIMENTO unset() all'interno di una funzione, solo la variabile locale è distrutta. La variabile nell'ambiente chiamante manterrà lo stesso valore di prima che fosse chiamato unset().

quindi è necessario passare la matrice genitore e il tasto per cancellare quella variabile:

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

Grazie, Gumbo! Ho cercato degli indizi sulla pagina dei "riferimenti" del manuale e ho mancato il punto con 'unset' e l'ambito. – sevenWonders

0

Non so se questo è il caso, ma quando avevo bisogno di cambiare i valori in modo ricorsivo in serie , avevo bisogno di passare & anche al valore 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); 
      } 
     } 
    } 
Problemi correlati