2012-05-03 83 views
21

有许多使用点符号访问PHP数组的提示和代码示例,但是我想做一些相反的事情。我想借一个多维数组是这样的:PHP - 使用点符号键将多维数组转换为二维数组

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

,把它变成这个(可能通过一些递归函数):

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

我想array_walk_recursive也许能帮助我建立新的钥匙,因为它似乎是它可以做很多繁重的递归的,但它不提供*的所有*键阵列。例如,在$ myArray上使用array_walk_recursive(通过PHP文档页面上的示例函数运行)只会向我提供没有数组值的键。我正在继续尝试使用一些很好的旧foreach循环来编写我自己的递归函数,但这是漫长的一天,正在伤害我的头。我会继续努力,如果我得到它(或更接近) – TheCheese

回答

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

输出

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

演示:http://codepad.org/YiygqxTM

我需要去,但如果需要,明天的说明,问我。

+5

+1 Nice Answer!... –

+0

这是一个比我想象的更好的答案!我之前没有玩过RecursiveIteratorIterator(但现在我会),所以它甚至没有穿过我的脑海。做得太好了! – TheCheese

+0

我从来没有见过或听说过这种方法。真棒回答。 – maiorano84

0

你可以不喜欢这样,但克里斯的答案应该是优选的:

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

这将处理嵌套的任意级别:

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

这是我对递归解决方案,适用于任何深度的数组:

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

这可以被称为$newArray = convertArray($myArray)

0

这是另一种类似于上面的Blafrat的方法 - 但仅处理数组作为值。

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

(这不会赶上的唯一情况是,你有这样的联想是,但第一个关键是0的值)

注意,RecursiveIteratorIterator可以比普通的递归函数慢。 https://xenforo.com/community/threads/php-spl-why-is-recursiveiteratoriterator-100x-slower-than-recursive-search.57572/

在这种情况下使用用于1000个迭代php5.6给出的样本阵列,这个代码是快两倍(递归= 0.032 VS迭代符= 0.062) - 但不同的是可能微不足道对于大多数情况。主要我喜欢递归,因为我发现Iterator的逻辑对于这样一个简单的用例来说是不必要的复杂的。

2

已有RecursiveIteratorIterator的答案。但这里是一个更优化解决方案,即避免使用嵌套循环

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

有需要在这里提出几点。请注意在这里不断使用RecursiveIteratorIterator::SELF_FIRST。这是很重要的,因为默认的是RecursiveIteratorIterator::LEAVES_ONLY,它不会让我们访问所有的密钥。所以在这个常量集合中,我们从数组的顶层开始深入。这种方法可以让我们存储密钥的历史记录,并在我们使用RecursiveIteratorIterator::getDepth方法的富叶时准备密钥。

Here is a working demo.

+1

不错的基于堆栈的方法 – goat