2012-05-03 80 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