2011-12-04 149 views
2

鑑於我有一個數組:拼合多維關聯數組引用的一個一維數組中的PHP

$array = array(
    'a' => array(
     'b' => array(
      'c' => 'hello', 
     ), 
    ), 
    'd' => array(
     'e' => array(
      'f' => 'world', 
     ), 
    ), 
); 

我想「壓扁」它引用的一維查找,串聯鍵與分隔符(在這個例子中,正斜槓/

一個成功的輸出執行var_dump()將產生:(記下所有引用

array(6) { 
    ["a"]=> 
    &array(1) { 
    ["b"]=> 
    &array(1) { 
     ["c"]=> 
     &string(5) "hello" 
    } 
    } 
    ["a/b"]=> 
    &array(1) { 
    ["c"]=> 
    &string(5) "hello" 
    } 
    ["a/b/c"]=> 
    &string(5) "hello" 
    ["d"]=> 
    &array(1) { 
    ["e"]=> 
    &array(1) { 
     ["f"]=> 
     &string(5) "world" 
    } 
    } 
    ["d/e"]=> 
    &array(1) { 
    ["f"]=> 
    &string(5) "world" 
    } 
    ["d/e/f"]=> 
    &string(5) "world" 
} 
array(2) { 
    ["a"]=> 
    &array(1) { 
    ["b"]=> 
    &array(1) { 
     ["c"]=> 
     &string(5) "hello" 
    } 
    } 
    ["d"]=> 
    &array(1) { 
    ["e"]=> 
    &array(1) { 
     ["f"]=> 
     &string(5) "world" 
    } 
    } 
} 

既然這樣,我用這樣的:

function build_lookup(&$array, $keys = array()){ 
    $lookup = array(); 
    foreach($array as $key => &$value){ 
     $path = array_merge($keys, (Array) $key); 
     $lookup[implode('/', $path)] = &$value; 
     if(is_array($value)){ 
      $lookup = array_merge($lookup, build_lookup($value, $path)); 
     } 
    } 
    return $lookup; 
} 

不過,我試圖改善它通過消除遞歸(切換到堆棧/流行的做法)元素這樣做的問題是參考保存,因爲典型的遞歸 - 非遞歸方法如下:

​​

...失敗並帶有引用。

我已經看到了一些類似的問題/上SO答案,但其中沒有用引用適當處理(因爲它不是提問者的意圖

有沒有更好的(讀取速度更快 )在這裏?


最終的解決方案(感謝@克里斯):

/** 
* 
* @return array 
*/ 
public function get_lookup_array() 
{ 
    $stack = $lookup = array(); 
    try 
    { 
     foreach($this->_array as $key => &$value) 
     { 
      $stack[$key] = &$value; 
     } 
     while(!empty($stack)) 
     { 
      $path = key($stack); 
      $lookup[$path] = &$stack[$path]; 
      if(is_array($lookup[$path])) 
      { 
       foreach($lookup[$path] as $key => &$value) 
       { 
        $stack[$path . $this->_separator . $key] = &$value; 
       } 
      } 
      unset($stack[$path]); 
     } 
    } 
    catch(\Exception $exception) 
    { 
     return false; 
    } 
    return $lookup; 
} 
+0

我最終可能會借用數據驅動陣列提取方法。也就是說,給定不同的源陣列,有一種方法可以根據每個路徑提供一系列路徑,最終得到一致的結果。酷解決方案,夥計們! – Trenton

回答

2
header('content-type:text/plain'); 

$arr = array(
    'a' => array(
     'b' => array(
      'c' => 'hello', 
     ), 
    ), 
    'd' => array(
     'e' => array(
      'f' => 'world', 
     ), 
    ), 
); 

//prime the stack using our format 
$stack = array(); 
foreach ($arr as $k => &$v) { 
    $stack[] = array(
     'keyPath' => array($k), 
     'node' => &$v 
    ); 
} 

$lookup = array(); 

while ($stack) { 
    $frame = array_pop($stack); 
    $lookup[join('/', $frame['keyPath'])] = &$frame['node']; 
    if (is_array($frame['node'])) { 
     foreach ($frame['node'] as $key => &$node) { 
      $keyPath = array_merge($frame['keyPath'], array($key)); 
      $stack[] = array(
       'keyPath' => $keyPath, 
       'node' => &$node 
      ); 
      $lookup[join('/', $keyPath)] = &$node; 
     } 
    } 
} 


var_dump($lookup); 
// check functionality 
$lookup['a'] = 0; 
$lookup['d/e/f'] = 1; 
var_dump($arr); 

或者你可以做這樣的東西得到一個參考/ W array_pop功能

end($stack); 
$k = key($stack); 
$v = &$stack[$k]; 
unset($stack[$k]); 

這是可行的,因爲php數組有按鍵創建排序的元素時間。 unset()刪除密鑰,並因此重置該密鑰的創建時間。

+0

謝謝@chris - 整個下午我都一直在這裏打瞌睡。使用你的答案和我以前的嘗試作爲參考,我想出了一些簡潔而實用的東西。你明白了,因爲我的解決方案實際上只是你的一個語法變體。我會用最後的方法體更新我的問題。 – Dan

+0

看起來不錯。我更喜歡你的 - 你擺脫了很多函數調用的開銷。 – goat