2011-12-04 91 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