在 PHP 中将多维关联数组展平为一维引用数组

Posted

技术标签:

【中文标题】在 PHP 中将多维关联数组展平为一维引用数组【英文标题】:Flatten multidimensional associative array to one one-dimensional array of references in PHP 【发布时间】:2012-01-12 16:17:58 【问题描述】:

鉴于我有一个数组:

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

但是,我试图通过删除递归元素来改进它(切换到堆栈/弹出方法)这样做的问题是引用保留,因为典型的递归- 非递归方法:

$stack = $input;
while(!empty($stack))
    $current = array_pop($stack);
    // do stuff and push to stack;

...引用失败。

我在 SO 上看到了一些类似的问题/答案,但没有一个适当地处理引用(因为这不是提问者的意图

这里有更好的(阅读速度)方法吗?


最终解决方案(感谢@chris):

/**
 *
 * @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;

【问题讨论】:

我最终可能会借用它来实现数据驱动的数组提取方法。也就是说,给定不同的源数组,有一种方法可以提供一系列基于每个路径的路径,最终得到统一的结果。很酷的解决方案,伙计们! 【参考方案1】:
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() 删除密钥,从而重置该密钥的创建时间。

【讨论】:

谢谢@chris - 整个下午我一直在搞这个。使用您的回答和我之前的尝试作为参考,我想出了一些简洁实用的东西。不过你明白了,因为我的解决方案实际上只是你的一个语法变体。我将使用最终方法主体更新我的问题。 看起来不错。我更喜欢你的——你摆脱了很多函数调用开销。

以上是关于在 PHP 中将多维关联数组展平为一维引用数组的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PHP 中将多维数组“展平”为简单数组? [复制]

php中的二维多维数组到一维数组[重复]

在php中将一维数组转换为多维数组[重复]

在 Symfony2 中将多维数组转换为点表示法

如何在php中将stdobj数组转换为关联数组

使用rest参数将参数展平为一维数组