2009-12-10 4 views
8

Voici un tableau exemple:PHP convertit un tableau imbriqué en un seul tableau tout en concaténant des clés?

$foo = array(
      'employer' => array(
        'name' => 'Foobar Inc', 
        'phone' => '555-555-5555' 
        ), 
      'employee' => array(
        'name' => 'John Doe', 
        'phone' => '555-555-5556', 
        'address' => array(
          'state' => 'California', 
          'zip' => '90210' 
         ) 
        ), 
      'modified' => '2009-12-01', 
     ); 

Je voudrais obtenir un résultat comme celui-ci:

$fooCompressed = array(
      'employer_name' => 'Foobar Inc', 
      'employer_phone' => '555-555-5555', 
      'employee_name' => 'John Doe', 
      'employee_phone' => '555-555-5556' 
      'employee_address_state' => 'California', 
      'employee_address_zip' => '90210', 
      'modified' => '2009-12-01' 
      ) 

Comment pourrais-je aller à écrire une fonction récursive pour gérer cette situation?

Répondre

13

Quelque chose comme ceci:

function makeNonNestedRecursive(array &$out, $key, array $in){ 
    foreach($in as $k=>$v){ 
     if(is_array($v)){ 
      makeNonNestedRecursive($out, $key . $k . '_', $v); 
     }else{ 
      $out[$key . $k] = $v; 
     } 
    } 
} 

function makeNonNested(array $in){ 
    $out = array(); 
    makeNonNestedRecursive($out, '', $in); 
    return $out; 
} 

// Example 
$fooCompressed = makeNonNested($foo); 
+0

+1 Ceci est assez proche de ce que je ferais. Parce que les clés sont en cours de modification, il n'y a pas de fonction intégrée qui le fera pour vous, et vous avez certainement besoin de récursion pour explorer les sous-valeurs qui sont également des tableaux. – zombat

+0

bon exemple. J'aime l'idée de passer le tableau de sortie par référence. – GSto

3

Voici une fonction qui vous permet de spécifier un préfixe de niveau supérieur via le second paramètre:

function flatten_array($array, $prefix = null) { 
    if ($prefix) $prefix .= '_'; 

    $items = array(); 

    foreach ($array as $key => $value) { 
    if (is_array($value)) 
     $items = array_merge($items, flatten_array($value, $prefix . $key)); 
    else 
     $items[$prefix . $key] = $value; 
    } 

    return $items; 
} 
0
/** 
* Flatten a multi-dimensional array or a nested object, constructing concatenated keys for 
* nested elements. 
* @param array or object $array - the array or object to be flattened 
* @param array or string $key_path - current parent keys path. 
* Pass this parameter as string if you need to set a common prefix for all keys 
* @param string $level_separator - keys concatenation glue 
* @param array $flat - resulting flattened array (omit this parameter when calling the function) 
* @return single-dimensional array with all array keys as concatenated keys of elements' 
* paths through the data structure 
*/ 
function flattenArray($array, &$key_path = array(), $level_separator = '.', &$flat = array()) 
{ 
     if(!is_array($key_path)) 
     { 
      // sanitize key_path 
      $key_path = array((string)$key_path); 
     } 
     foreach($array as $key => $value) 
     { 
      // push current key to path 
      array_push($key_path, $key); 

      if(is_array($value) || is_object($value)) 
      { 
       // next level recursion 
       $flat = array_merge($flat, flattenArray($value, $key_path, $level_separator, $flat)); 
      } 
      else 
      { 
        // write the value directly 
        $flat[implode($level_separator, $key_path)] = $value; 
       } 

       // remove used key 
       array_pop($key_path); 
     } 

     return $flat; 
    } 
0

Après quelques itérations, je J'ai été capable d'affiner une solution à ce problème qui utilise une approche basée sur une pile pour éviter la récursivité, simplifiant un peu les choses.

/*** 
* @name array_flatten 
* @author Tom Penzer @tpenzer 
* Flattens a multi-tiered array into a single-tiered 
* associative array with keys reflective of their 
* values' hierarchy. 
* 
* @param array $array  Required - the multi- 
* level keyed array to be flattened 
* @param string $separator Optional - the string 
* used to separate the keys from different levels of 
* the hierarchy 
* 
* @return array a single-level keyed array 
***/ 
function array_flatten($array, $separator = '_') { 
    $output = array(); 

    while (list($key, $value) = each($array)) { 
     if (is_array($value)) { 
      $build = array(); 
      foreach ($value as $s_key => $s_value) { 
       $build[$key . $separator . $s_key] = $s_value; 
      } 
      unset($array[$key]); 
      $array = $build + $array; 
      unset($build); 
      continue;//skip write to $output 
     } 
     $output[$key] = $value; 
     unset($array[$key]); 
    } 

    return $output; 
} 

Pas exactement la méthode demandée, mais il est un joli contraste avec les approches récursives au problème.

3

Je pense que ce « truc » à l'aide est http_build_query est moins d'une pollution visuelle w/out récursion (ou du moins laisser php faire pour vous)

3 lignes de code si votre str_replace utilise les valeurs de code URL pour [et]

$string  = http_build_query($array); 
$string  = urldecode($string); 
$string  = str_replace(
        array('[',']'), 
        array('_','') , 
        $string 
       ); 
parse_str($string, $flat_array); 

flat_array $ devient:

array(7) { 
    ["employer_name"]   =>"Foobar Inc" 
    ["employer_phone"]  =>"555-555-5555" 
    ["employee_name"]   =>"John Doe" 
    ["employee_phone"]  =>"555-555-5556" 
    ["employee_address_state"]=>"California" 
    ["employee_address_zip"] =>"90210" 
    ["modified"]    =>"2009-12-01" 
} 
Questions connexes