2012-05-03 15 views
21

Existen muchos consejos y ejemplos de códigos para acceder a las matrices PHP con notación de puntos, pero me gustaría hacer algo al revés. Me gustaría tener una matriz multidimensional como esto:PHP - Convertir matriz multidimensional en matriz 2D con teclas de notación de puntos

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

y convertirlo en esto (probablemente a través de una función recursiva):

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

pensé array_walk_recursive podría ser capaz de ayudar a mí para construir las nuevas claves, ya que parecía que podría hacer mucho del trabajo pesado con recursividad pero no proporciona * todos * las llaves del formación. Por ejemplo, el uso de array_walk_recursive en $ myArray (como se ejecuta a través de la función de ejemplo en la página de documentación de PHP) solo me proporcionaría las claves que no tienen valores de matriz. Continúo intentando escribir mi propia función recursiva con algunos viejos y buenos bucles foreach, pero ha sido un día largo y me duele la cabeza. Seguiré yendo y actualizaré si lo consigo (o más cerca) – TheCheese

Respuesta

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

salida

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

demo: http://codepad.org/YiygqxTM

tengo que ir, pero si necesita una explicación de que mañana, en mi opinión.

+5

+1 ¡Buena respuesta! ... –

+0

¡Esta es una respuesta 1000% mejor de lo que pensé que encontraría! No he jugado antes con RecursiveIteratorIterator (pero lo haré ahora), así que ni siquiera se me pasó por la cabeza. ¡Muy bien hecho! – TheCheese

+0

Nunca había visto o escuchado hablar de este método antes. Impresionante respuesta. – maiorano84

0

Usted puede hacerlo de esta manera, pero la respuesta de Chris debería estar preferido:

<?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

Este se encargará de un nivel arbitrario de anidación:

<? //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

Esta es mi opinión sobre una solución recursiva, que trabaja para las matrices de cualquier profundidad:

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

que puede ser llamado como $newArray = convertArray($myArray) .

0

Este otro enfoque similar al anterior Blafrat, pero maneja simplemente matrices como valores.

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

(El único caso que esto no es atrapar en la que tuvo un valor que era asociativo, pero la primera clave era 0.)

Tenga en cuenta que la RecursiveIteratorIterator puede ser más lenta que la función recursiva regular. https://xenforo.com/community/threads/php-spl-why-is-recursiveiteratoriterator-100x-slower-than-recursive-search.57572/

En este caso el uso de la matriz de muestra dada para 1000 iteraciones php5.6, este código es dos veces más rápido (recursiva = 0,032 vs interator = 0,062) - pero la diferencia es probablemente insignificante para la mayoría de los casos. Principalmente prefiero recursivo porque la lógica del iterador me resulta innecesariamente complicada para un caso de uso simple como este.

2

Ya existe la respuesta con RecursiveIteratorIterator. Pero aquí es una solución más óptima, que evita el uso de bucles anidados:

$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; 
    } 
} 

Hay necesitan ser hecho aquí varios puntos. Observe el uso de la constante RecursiveIteratorIterator::SELF_FIRST aquí. Es importante ya que el predeterminado es RecursiveIteratorIterator::LEAVES_ONLY que no nos permite acceder a todas las claves. Entonces, con este conjunto constante, comenzamos desde el nivel superior de una matriz y profundizamos. Este enfoque nos permite almacenar el historial de claves y preparar la clave cuando enriquecemos hojas usando el método RecursiveIteratorIterator::getDepth.

Here is a working demo.

+1

buen enfoque basado en la pila – goat

Cuestiones relacionadas