2012-05-03 9 views
21

Ci sono un sacco di suggerimenti ed esempi di codici disponibili per accedere agli array PHP con notazione dot, ma mi piacerebbe fare un po 'il contrario. Vorrei prendere un array multidimensionale come questo:PHP - Conversione di array multidimensionali in array 2D con tasti di notazione dot

$myArray = array(
    'key1' => 'value1', 
    'key2' => array(
     'subkey' => 'subkeyval' 
    ), 
    'key3' => 'value3', 
    'key4' => array(
     'subkey4' => array(
      'subsubkey4' => 'subsubkeyval4', 
      'subsubkey5' => 'subsubkeyval5', 
     ), 
     'subkey5' => 'subkeyval5' 
    ) 
); 

e trasformarlo in questa (probabilmente attraverso qualche funzione ricorsiva):

$newArray = array(
    'key1'     => 'value1', 
    'key2.subkey'    => 'subkeyval', 
    'key3'     => 'value3', 
    'key4.subkey4.subsubkey4' => 'subsubkeyval4', 
    'key4.subkey5.subsubkey5' => 'subsubkeyval5', 
    'key4.subkey5'   => 'subkeyval5' 
); 
+0

ho pensato array_walk_recursive potrebbe essere in grado di aiutarmi a costruire le nuove chiavi in ​​quanto sembrava che potesse fare un sacco di sollevamento di carichi pesanti con la ricorsione, ma non fornisce * tutte * le chiavi del array. Ad esempio, l'uso di array_walk_recursive su $ myArray (come eseguito attraverso la funzione di esempio nella pagina di documentazione di PHP) mi fornisce solo le chiavi che non hanno valori di array. Sto continuando a provare a scrivere la mia funzione ricorsiva con un buon vecchio ciclo foreach ma è stata una lunga giornata e mi fa male la testa. Continuerò a farlo e aggiornerò se lo avrò (o più vicino) – TheCheese

risposta

59

teh codez

$ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($myArray)); 
$result = array(); 
foreach ($ritit as $leafValue) { 
    $keys = array(); 
    foreach (range(0, $ritit->getDepth()) as $depth) { 
     $keys[] = $ritit->getSubIterator($depth)->key(); 
    } 
    $result[ join('.', $keys) ] = $leafValue; 
} 

uscita

Array 
(
    [key1] => value1 
    [key2.subkey] => subkeyval 
    [key3] => value3 
    [key4.subkey4.subsubkey4] => subsubkeyval4 
    [key4.subkey4.subsubkey5] => subsubkeyval5 
    [key4.subkey5] => subkeyval5 
) 

demo: http://codepad.org/YiygqxTM

ho bisogno di andare, ma se avete bisogno di una spiegazione di che domani, mi chiedo.

+5

+1 Bella risposta! ... –

+0

Questa è una risposta del 1000% migliore di quanto pensassi di trovare! Non ho mai giocato con RecursiveIteratorIterator prima (ma lo farò ora) quindi non mi è nemmeno passato per la testa. Molto ben fatto! – TheCheese

+0

Non ho mai visto o sentito questo metodo prima. Risposta fantastica – maiorano84

0

Si potrebbe fare in questo modo, ma la risposta di Chris dovrebbe essere preferito:

<?php 
$array = array(); 
foreach($myArray as $key=>$value){ 
    //1st level 
    if(is_array($value)){ 
     //2nd level 
     foreach($value as $key_b=>$value_b){ 
      //3rd level 
      if(is_array($value_b)){ 
       foreach($value_b as $key_c=>$value_c){ 
        $array[$key.'.'.$key_b.'.'.$key_c]=$value_c; 
       } 
      }else{ 
       $array[$key.'.'.$key_b]=$value_b; 
      } 
     } 
    }else{ 
     $array[$key]=$value; 
    } 
} 

print_r($array); 
/* 
Array 
(
[key1] => value1 
[key2.subkey] => subkeyval 
[key3] => value3 
[key4.subkey4.subsubkey4] => subsubkeyval4 
[key4.subkey4.subsubkey5] => subsubkeyval5 
[key4.subkey5] => subkeyval5 
) 
*/ 
4

Questa gestirà un livello arbitrario di nidificazione:

<? //PHP 5.4+ 
$dotFlatten = static function(array $item, $context = '') use (&$dotFlatten){ 
    $retval = []; 
    foreach($item as $key => $value){ 
     if (\is_array($value) === true){ 
      foreach($dotFlatten($value, "$context$key.") as $iKey => $iValue){ 
       $retval[$iKey] = $iValue; 
      } 
     } else { 
      $retval["$context$key"] = $value; 
     } 
    } 
    return $retval; 
}; 

var_dump(
    $dotFlatten(
     [ 
      'key1' => 'value1', 
      'key2' => [ 
       'subkey' => 'subkeyval', 
      ], 
      'key3' => 'value3', 
      'key4' => [ 
       'subkey4' => [ 
        'subsubkey4' => 'subsubkeyval4', 
        'subsubkey5' => 'subsubkeyval5', 
       ], 
       'subkey5' => 'subkeyval5', 
      ], 
     ] 
    ) 
); 
?> 
1

Questo è il mio introito su una soluzione ricorsiva, che lavora per gli array di qualsiasi profondità:

function convertArray($arr, $narr = array(), $nkey = '') { 
    foreach ($arr as $key => $value) { 
     if (is_array($value)) { 
      $narr = array_merge($narr, convertArray($value, $narr, $nkey . $key . '.')); 
     } else { 
      $narr[$nkey . $key] = $value; 
     } 
    } 

    return $narr; 
} 

che può essere chiamato come $newArray = convertArray($myArray) .

0

Questo altro approccio simile a Blafrat sopra, ma gestisce semplicemente gli array come valori.

function dot_flatten($input_arr, $return_arr = array(), $prev_key = '') 
{ 
    foreach ($input_arr as $key => $value) 
    { 
     $new_key = $prev_key . $key; 

     // check if it's associative array 99% good 
     if (is_array($value) && key($value) !==0 && key($value) !==null) 
     { 
      $return_arr = array_merge($return_arr, dot_flatten($value, $return_arr, $new_key . '.')); 
     } 
     else 
     { 
      $return_arr[$new_key] = $value; 
     } 
    } 

    return $return_arr; 
} 

(L'unico caso questo non sarebbe la cattura è dove si ha un valore che era associativa ma la prima chiave è stata 0.)

Si noti che il RecursiveIteratorIterator può essere più lento di normale funzione ricorsiva. https://xenforo.com/community/threads/php-spl-why-is-recursiveiteratoriterator-100x-slower-than-recursive-search.57572/

In questo caso utilizzando la matrice del campione indicata per 1000 iterazioni php5.6, questo codice è due volte più veloce (ricorsiva = 0,032 vs interator = .062) - ma la differenza è probabilmente insignificante per la maggior parte dei casi. Principalmente preferisco ricorsivo perché trovo la logica dell'Iterator inutilmente complicata per un caso di uso semplice come questo.

2

C'è già la risposta con RecursiveIteratorIterator. Ma qui è una soluzione più ottimale , che evita di utilizzare cicli annidati:

$iterator = new RecursiveIteratorIterator(
    new RecursiveArrayIterator($arr), 
    RecursiveIteratorIterator::SELF_FIRST 
); 
$path = []; 
$flatArray = []; 

foreach ($iterator as $key => $value) { 
    $path[$iterator->getDepth()] = $key; 

    if (!is_array($value)) { 
     $flatArray[ 
      implode('.', array_slice($path, 0, $iterator->getDepth() + 1)) 
     ] = $value; 
    } 
} 

Ci sono diversi punti devono essere fatte qui. Si noti l'uso della costante RecursiveIteratorIterator::SELF_FIRST qui. È importante poiché quello predefinito è RecursiveIteratorIterator::LEAVES_ONLY che non ci consente di accedere a tutte le chiavi. Quindi, con questo set costante, partiamo dal livello più alto di un array e andiamo più a fondo. Questo approccio ci consente di memorizzare la cronologia delle chiavi e preparare la chiave quando siamo ricchi di foglie utilizzando il metodo RecursiveIteratorIterator::getDepth.

Here is a working demo.

+1

approccio basato sullo stack – goat

Problemi correlati