2013-06-08 10 views
5

Scaviamo nel problema principale subito, ho l'ingresso come questoCome si formattano i dati del modello di set annidato in una matrice?

$category = array(
    'A' => array('left' => 1, 'right' => 8), 
    'B' => array('left' => 2, 'right' => 3), 
    'C' => array('left' => 4, 'right' => 7), 
    'D' => array('left' => 5, 'right' => 6), 
    'E' => array('left' => 9, 'right' => 10), 
); 

voglio l'uscita di essere qualcosa di simile

$tree = array(
    array('A', 'B'), 
    array('A', 'C', 'D'), 
    array('E'), 
); 

quale è la funzione migliore e veloce per ciclo anche se l'array di input e creare il risultato di output come questo?

+0

È necessario includere la logica aziendale della conversione dalla prima struttura al secondo. Non è molto chiaro adesso. –

+0

L'output desiderato non riflette un set nidificato. dovrebbe essere più simile a 'array (A => array (B => null, C => array (D => null), E => null)' –

+0

@hw la logica aziendale qui è http: //en.wikipedia. org/wiki/Nested_set_model –

risposta

15

Lavorare con un set annidato è un caso perfetto per la ricorsione.

Dato i dati:

$category = array(
    'A' => array('left' => 1, 'right' => 9), 
    'B' => array('left' => 2, 'right' => 4), 
    'C' => array('left' => 5, 'right' => 8), 
    'D' => array('left' => 6, 'right' => 7), 
    'E' => array('left' => 10, 'right' => 11), 
); 

Di seguito si romperà i dati impostati annidati in giù in una matrice correttamente nidificato in PHP:

function createTree($category, $left = 0, $right = null) { 
    $tree = array(); 
    foreach ($category as $cat => $range) { 
     if ($range['left'] == $left + 1 && (is_null($right) || $range['right'] < $right)) { 
      $tree[$cat] = createTree($category, $range['left'], $range['right']); 
      $left = $range['right']; 
     } 
    } 
    return $tree; 
} 

$tree = createTree($category); 
print_r($tree); 

uscita:

Array 
(
    [A] => Array 
     (
      [B] => Array 
       (
       ) 

      [C] => Array 
       (
        [D] => Array 
         (
         ) 

       ) 

     ) 

    [E] => Array 
     (
     ) 

) 

Poi si puoi appiattire l'albero corretto nel formato desiderato con il seguente:

function flattenTree($tree, $parent_tree = array()) { 
    $out = array(); 
    foreach ($tree as $key => $children) { 
     $new_tree = $parent_tree; 
     $new_tree[] = $key; 
     if (count($children)) { 
      $child_trees = flattenTree($children, $new_tree); 
      foreach ($child_trees as $tree) { 
       $out[] = $tree; 
      } 
     } else { 
      $out[] = $new_tree; 
     } 
    } 
    return $out; 
} 

$tree = flattenTree($tree); 
print_r($tree); 

uscita:

Array 
(
    [0] => Array 
     (
      [0] => A 
      [1] => B 
     ) 

    [1] => Array 
     (
      [0] => A 
      [1] => C 
      [2] => D 
     ) 

    [2] => Array 
     (
      [0] => E 
     ) 

) 
+1

La tua funzione funziona, molte grazie :) –

+0

@quocnguyen - Cheers –

0

Se non volete usare la ricorsione:

foreach ($category as $name => $range) { 
    $line[$range['left']] = $name; 
    $line[$range['right']] = $name; 
} 

ksort($line); 
$count = 0; 

foreach($line as $name) { 
    if (! isset($open[$name])) { 
     $open[$name] = true; 
     $result[$name] = true; 
     $count++; 
    } else { 
     unset($open[$name]); 
     if ($count > 0) { 
      $count = 0; 
      $tree[] = array_keys($result); 
      $result = $open; 
     } else { 
      $result = array(); 
     } 
    } 
} 
+0

La ricorsione è necessaria per gestire livelli potenzialmente infiniti di nidificazione. Hai provato questo? –

0

Un'altra soluzione, senza ricorsione (test si prega)

$result = array(); 

    foreach($category as $key => $value) { 

     /*Get current row index*/ 
     $i = count($result); 

     if($i == 0) { 
      $result[] = array($key); 
     } else { 

      $iParent = -1; 

      /*Find parent index*/ 
      for($j = count($result[$i-1]) - 1; $j >= 0; $j--) { 
       if($value['left'] > $category[$result[$i-1][$j]]['left'] 
        && $value['right'] < $category[$result[$i-1][$j]]['right']) { 
        $iParent = $j; 
        break; 
       } 
      } 

      if($iParent == -1) { $result[] = array($key);} 

      if($iParent == count($result[$i-1]) - 1) { 
       // append to last 
       $result[$i-1][] = $key; 
      } else { 
       // make new list 
       $result[$i] = array_slice($result[$i-1], 0, $iParent + 1); 
       $result[$i][] = $key; 
      } 
     } 
    } 

    print_r($result); 
0

C'è un bug con la funzione di cui sopra. La categoria superiore del secondo array di @tree viene rimossa. Questa è la soluzione:

foreach ($category as $name => $range) { 
    $line[$range['left']] = $name; 
    $line[$range['right']] = $name; 
} 

ksort($line); 
$tree = array(); 
$count = 0; 

foreach ($line as $name) { 
    if (!isset($open[$name])) { 
     $open[$name] = true; 
     $count++; 
    } 
    else { 
     if ($count > 0) { 
      $count = 0; 
      $tree[] = array_keys($open); 
     } 
     unset($open[$name]); 
    } 
} 
0

Ho modificato poco il codice di Stiven.

public function createTree($category, $left = 0, $right = null) { 
    $tree = array(); 
    foreach ($category as $cat => $range) { 
     if ($range['clf'] == $left + 1 && (is_null($right) || $range['crt'] < $right)) { 
      $tree[$cat]= array(); 
      $tree[$cat]['title']=$range['title']; 
      if($range['crt']-$range['clf']>1){ 
       $tree[$cat]['sub'] = $this->createTree($category, $range['clf'], $range['crt']); 
      } 
      $left = $range['crt']; 
     } 
    } 
    return $tree; 
} 
Problemi correlati