2012-01-12 19 views
24

Ho guardato in Internet e non ho ancora trovato quello che sto cercando. Ho una matrice piatta con ogni elemento contenente un 'id' e un 'parent_id'. Ogni elemento avrà un solo genitore, ma potrebbe avere più figli. Se parent_id = 0, viene considerato un elemento di livello root. Sto cercando di ottenere il mio array piatto su un albero. Gli altri esempi che ho trovato copiano solo l'elemento sul genitore, ma l'originale esiste ancora.Creare un albero da un array piatto in PHP

EDIT

Ogni elemento della matrice di partenza viene letto da un file XML separato. Il file stesso avrà '0' come valore per parent_id se non ha un genitore. I tasti sono in realtà stringhe.

Mi dispiace per la confusione precedente. Speriamo che questo sia più chiaro:

/EDIT

La mia matrice di partenza:

 
Array 
(
    [_319_] => Array 
     (
      [id] => 0 
      [parent_id] => 0 
     ) 

    [_320_] => Array 
     (
      [id] => _320_ 
      [parent_id] => 0 
     ) 

    [_321_] => Array 
     (
      [id] => _321_ 
      [parent_id] => _320_ 
     ) 

    [_322_] => Array 
     (
      [id] => _322_ 
      [parent_id] => _321_ 
     ) 

    [_323_] => Array 
     (
      [id] => _323_ 
      [parent_id] => 0 
     ) 

    [_324_] => Array 
     (
      [id] => _324_ 
      [parent_id] => _323_ 
     ) 

    [_325_] => Array 
     (
      [id] => _325_ 
      [parent_id] => _320_ 
     ) 
)

La matrice risultante dopo che l'albero è fatto:

 
Array 
(
    [_319_] => Array 
     (
      [id] => _319_ 
      [parent_id] => 0 
     ) 

    [_320_] => Array 
     (
      [id] => _320_ 
      [parent_id] => 0 
      [children] => Array 
       (
        [_321_] => Array 
         (
          [id] => _321_ 
          [parent_id] => _320_ 
          [children] => Array 
           (
            [_322_] => Array 
             (
              [id] => _322_ 
              [parent_id] => _321_ 
             ) 
           ) 
         ) 
        [_325_] => Array 
         (
          [id] => _325_ 
          [parent_id] => _320_ 
         ) 
       ) 
    [_323_] => Array 
     (
      [id] => _323_ 
      [parent_id] => 0 
      [children] => Array 
       (
        [_324_] => Array 
         (
          [id] => _324_ 
          [parent_id] => _323_ 
         ) 
       ) 
     ) 

Qualsiasi aiuto/consiglio è molto apprezzato!

Alcuni codice che ho finora:

 

     function buildTree(array &$elements, $parentId = 0) { 
     $branch = array(); 

     foreach ($elements as $element) { 
      if ($element['parent_id'] == $parentId) { 
       $children = $this->buildTree($elements, $element['id']); 
       if ($children) { 
        $element['children'] = $children; 
       } 
       $branch[] = $element; 
      } 
     } 

     return $branch; 
    } 

+1

Sono confuso. Ci stai solo chiedendo di scrivere il codice che prende il tuo pugno di array e sputa quello che hai nel secondo array? – MetalFrog

+0

Sì ... qual è la domanda qui? –

+0

In breve, credo di si. Ho esaminato vari altri esempi qui su StackOverflow e su altri blog/forum. Ma quando li ho provati non funzionano. – DSkinner

risposta

38

hai dimenticato il unset() in là fratello.

function buildTree(array &$elements, $parentId = 0) { 
    $branch = array(); 

    foreach ($elements as $element) { 
     if ($element['parent_id'] == $parentId) { 
      $children = buildTree($elements, $element['id']); 
      if ($children) { 
       $element['children'] = $children; 
      } 
      $branch[$element['id']] = $element; 
      unset($elements[$element['id']]); 
     } 
    } 
    return $branch; 
} 
+3

Questa soluzione potrebbe non riuscire a costruire correttamente l'albero in determinate circostanze (ad es.$ arr = array (array ('id' => 1, 'parentid' => 0), array ('id' => 10, 'parentid' => 2), array ('id' => 2, 'parentid '=> 0), array (' id '=> 3,' parentid '=> 10), array (' id '=> 4,' parentid '=> 0), array (' id '=> 11,' parentid '=> 1), array (' id '=> 5,' parentid '=> 0), array (' id '=> 6,' parentid '=> 1), array (' id '=> 8, 'parentid' => 11), array ('id' => 9, 'parentid' => 0), array ('id' => 7, 'parentid' => 0),);) Suggerirei: http://stackoverflow.com/questions/4196157/create-array-tree-from-array-list (soluzione modificata di Arthur) – danicotra

+1

Non salva i primi genitori senza figli. – mrded

+0

@Freedom_Ben grazie ci provo :) – n0nag0n

3

riesco a vedere la logica, tranne per questo nel risultato:

Array 
(
    [0] => Array 
     (
      [id] => 0 
      [parent_id] => 0 
     ) 

    [1] => Array 
     (
      [id] => 1 
      [parent_id] => 0 
     ) 

IMHO, è parent_id = o, non dovrebbe [1 ] essere un figlio di [0] qui?

In ogni caso, i riferimenti al salvataggio:

$tree = array(); 
foreach($inputarray as $item){ 
    if(!isset($tree[$item['id']])) $tree[$item['id']] = array(); 
    $tree[$item['id']] = array_merge($tree[$item['id']],$item); 
    if(!isset($tree[$item['parent_id']])) $tree[$item['parent_id']] = array(); 
    if(!isset($tree[$item['parent_id']]['children'])) $tree[$item['parent_id']]['children'] = array(); 
    $tree[$item['parent_id']]['children'][] = &$tree[$item['id']]; 
} 
$result = $tree[0]['children']; 
unset($tree); 
print_r($result); 

perché avete abusato 0 sia come un numero 'magico' come root, e un ID esistente, ora abbiamo la ricorsione nel id = 0 ramo. L'aggiunta di if($item['parent_id']!=$item['id']) prima del $tree[$item['parent_id']]['children'][] = &$tree[$item['id']]; potrebbe impedirlo, ma non è bello.

+0

+1 perché la ricusazione ha reso la memoria esaurita nel mio caso. Nel mio caso c'erano 54 oggetti e questo era sufficiente per soddisfare la mia memoria. – bumerang

2

E 'possibile costruire la matrice di origine leggermente diverso è possibile utilizzare questa funzione (parent_id, id, titolo):

$q = mysql_query("SELECT id, parent_id, name FROM categories"); 
while ($r = mysql_fetch_row($q)) { 
    $names[$r[0]] = $r[2]; 
    $children[$r[0]][] = $r[1]; 
} 

function render_select($root=0, $level=-1) { 
    global $names, $children; 
    if ($root != 0) 
    echo '<option>' . strrep(' ', $level) . $names[$root] . '</option>'; 
    foreach ($children[$root] as $child) 
    render_select($child, $level+1); 
} 

echo '<select>'; 
render_select(); 
echo '</select>'; 
  1. More efficient hierarchy system
0

si desidera essere guardando la memorizzazione e caricamento di dati gerarchici in MySQL poiché questo dovrebbe risolvere alcuni problemi. Suppongo che il primo array rappresenti i dati presi direttamente dal database?

Sembra che tu stia cercando di utilizzare il modello di adiacenza per organizzare i tuoi dati nella struttura gerarchica. Ci sono anche altri modi per ottenere ciò usando il nesting. Se non si stanno prendendo questi dati da un database, questo potrebbe non essere altrettanto utile.

Questo link vi possono aiutare: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

+0

Anche se illustra correttamente l'uso sia del modello di adiacenza come del set nidificato, in pratica (almeno, secondo la mia esperienza), il modello di set annidato è troppo costoso per le mutazioni (in media metà della tabella deve essere aggiornata!) per qualsiasi dato pratico. Se i dati sono relativamente stantii (cioè raramente cambia), allora è fattibile, ma di solito non è così. – Wrikken

+0

@Wrikken Sì, dipende da come i dati vengono utilizzati/aggiornati. Per le categorie va bene, ma per i dati con molte modifiche non è affatto fattibile. Ho dimenticato di dirlo, grazie :) –

5

Questo funziona per me:

$index=array(); 
$tree=array(); 
foreach ($ori as $key=>$var) { 
    $var=array_shift($ori); 
    if ($var['id']==0) $var['id']=$key; 
    if ((string)$var['parent_id']==='0') { 
    $tree[$key]=$var; 
    $index[$key]=&$tree[$key]; 
    } else if (isset($index[$var['parent_id']])) { 
    if (!isset($index[$var['parent_id']]['children'])) $index[$var['parent_id']]['children']=array(); 
    $index[$var['parent_id']]['children'][$key]=$var; 
    $index[$key]=&$index[$var['parent_id']]['children'][$key]; 
    } else { 
    array_push($ori,$var); 
    } 
} 
unset($index); 
print_r($tree); 
+0

Adoro l'uso dell'indice. Brillante. –

0

Ecco la mia soluzione, funziona idealmente, se si assume che il parent_id livello superiore = 0:

function MakeTree($arr){ 
    $parents_arr=array(); 
    foreach ($arr as $key => $value) { 
     $parents_arr[$value['pid']][$value['id']]=$value; 
    } 
    $tree=$parents_arr['0']; 
    $this->createTree($tree, $parents_arr); 
    return $tree; 
} 
function createTree(&$tree, $parents_arr){ 
    foreach ($tree as $key => $value) { 
     if(!isset($value['children'])) { 
      $tree[$key]['children']=array(); 
     } 
     if(array_key_exists($key, $parents_arr)){ 
      $tree[$key]['children']=$parents_arr[$key]; 
      $this->createTree($tree[$key]['children'], $parents_arr); 
     } 
    } 
} 
2

Anche se questa è una vecchia questione, sarò dopo la mia risposta qui:

/* assuming top level pid = 0 */ 
$rows = array (
    array ('id' => 1, 'pid' => 0), 
    /* ... */ 
); 

/* make id become array key */ 
$rows = array_column ($rows, null, 'id'); 

foreach ($rows as $key => $val) { 
    if ($val ['pid']) { 
     if (isset ($rows [$val ['pid']])) { 
      $rows [$val ['pid']]['children'][] = &$rows [$key]; 
     } 
    } 
} 

foreach ($rows as $key => $val) { 
    if ($val ['pid']) unset ($rows [$key]); 
} 

array_column è PHP 5.5 ma è possibile crearlo facilmente.

22

La soluzione di ImmortalFirefly funziona, tuttavia, come indicato da mrd, non salva i primi genitori senza figli. Ho modificato la funzione per risolvere questo problema:

function buildTree(array &$elements, $parentId = 0) { 

    $branch = array(); 

    foreach ($elements as &$element) { 

     if ($element['parent_id'] == $parentId) { 
      $children = buildTree($elements, $element['id']); 
      if ($children) { 
       $element['children'] = $children; 
      } 
      $branch[$element['id']] = $element; 
      unset($element); 
     } 
    } 
    return $branch; 
} 
+0

Hai appena salvato il mio 6. Il mio capo stava per picchiarmi a morte. Uff. Grazie mille amico. –

+0

Grazie! Proprio quello di cui avevo bisogno! – maxpower9000

0

Questa è la mia soluzione, copiare e ottimizzare altre soluzioni.

function buildTree(array &$elements, $parentId = 0) { 
    $branch = array(); 
    foreach ($elements as $key => $element) { 
     if ($element['parent_id'] == $parentId) { 
      $children = $this->buildTree($elements, $key); 
      if ($children) { 
       $element['children'] = $children; 
      } 
      $branch[$key] = $element; 
      unset($elements[$key]); 
     } 
    } 
    return $branch; 
} 
0

Pulito, corto e privo di zavorra. Matrice di array ad albero:

class Mother { 
    private $root; 
    public function treeInit($array) 
    { 
     $this->root = new Child(); 
     foreach($array as $value){ 
      $this->root->treeClimb(array_reverse($value)); 
     } 
     return $this->root; 
    } 
} 

class Child { 
    private $children = []; 
    public function treeClimb($arr) 
    { 
     if(count($arr) > 0) { 
      $childTmp = array_pop($arr); 
      if(!key_exists($childTmp,$this->children)) 
      { 
       $this->children[$childTmp] = new Child(); 
      } 
     $this->children[$childTmp]->treeClimb($arr); 
     } 
    } 
} 

$array = array(array('obst','banae','krumm','gelb'), 
        array('obst','beere','him'), 
        array('obst','beere','brom'), 
        array('obst','banae','gerade'), 
        array('veg','carot','gerade')); 

$obj = new Mother(); 
var_dump($obj->treeInit($array)); 
Problemi correlati