2010-12-01 13 views
6

que tiene un árbol de categorías de la siguiente estructura:recursividad y que pasa por referencia

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

Al lado de una subcategoría, cada categoría puede contener productos (como una carpeta puede contener subcarpetas y archivos sólo).

Estoy tratando de escribir una función recursiva que deseo tomar esta matriz como referencia y quitar ambas categorías de hoja con [productCount] = 0 y todas las categorías principales que contienen tales nodos vacíos. En otras palabras, después del procesamiento, quiero tener solo aquellas categorías que contienen productos en cualquier subnivel.

He escrito un código, ahora lo depura y no elimina los nodos vacíos. Puede ser que no estoy usando las referencias correctamente. Por favor, ayúdame a arreglarlo, si es posible.

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

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

+1

@Ghommey: Sí, en PHP una matriz vacía se considera faly. – BoltClock

Respuesta

4

También podría cambiar el parámetro en la función para tomar una serie de nodos en lugar de un solo nodo. Esto cambia la recursividad ligeramente, y evita la necesidad de pasar a lo largo de una tecla:

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

Además, añade un cheque que asegura que si se podan todos los nodos hijos, el padre (ahora, hoja) nodo también se poda.

Espero que esto ayude! datos


prueba:

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

La Llamada:

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

Resulta imposible utilizar 'unset ($ nodes [$ key]);' dentro de una función para modificar la matriz inicial que se pasa por referencia, ya que simplemente desarmará la variable de referencia dentro del alcance de las funciones. – sevenWonders

+0

@sevenWonders - Olvidé mencionar que probé este guión (así como el de Gumbo) y ambos funcionan. Prácticamente no hay diferencia, salvo que encuentro la clave dentro de la función llamada antes de desactivarla. – RabidFire

+0

@RabidFire - Extrañamente cuando pruebo tu función me sale un error "Solo se pueden pasar variables por referencia" en la línea 'pruneTree ($ nodes [$ key] ['children']);'. – sevenWonders

5

unset elimina sólo la referencia pero no la variable de referencia:

Si una variable que se pasa por referencia es unset() interior de una función, solo la variable local es destruida. La variable en el entorno de llamada conservará el mismo valor que antes de que se llamara unset().

lo que necesita para pasar la matriz de los padres y la tecla para borrar esa variable:

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

¡Gracias, Gumbo! He estado buscando pistas en la página de "referencias" del manual, y he perdido el punto con 'unset' y el alcance. – sevenWonders

0

No sé si este es el caso, pero cuando tenía que cambiar los valores de forma recursiva en conjunto , necesitaba pasar & al valor foreach también.

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