将关联数组转换为带有值的多维数组

6

这是一个有趣的情况,我已经为其创建了一个工作函数,但想知道是否有更简单的方法。

我有以下多维数组:

$foo = array(
    [0] => array(
        'keys' => array( 
            'key1' => 1,
            'key2' => a,
            'key3' => 123
        ),
       'values' => array(
            //goodies in here
        )
    )
    [1] => array(
        'keys' => array( 
            'key1' => 1,
            'key2' => b,
            'key3' => 456
        ),
       'values' => array(
            //goodies in here
        )
    )
)

我的目标是将这个转换为一个基于keys数组中的嵌套的多维数组,我所期望的输出结果是:

$bar = array(
    [1] => array(
        [a] => array(
            [123] => array( //values array from above )
        ),
        [b] => array(
            [456] => array( //values array from above )
        )
    )
)

密钥始终可以根据其在“keys”数组中的位置进行嵌套,但密钥本身并不总是相同的,“keys”处理用户定义的分组,因此顺序和值可能会更改。我也不希望有重复的键。

“array_merge”对我没有用处,因为在很多情况下,数组键实际上是数字ID。因此,这个函数有效 - 但我想知道是否自己制作了一双新的手套

   protected function convertAssociativeToMulti( &$output, $keys, $value )
   {
      $temp = array();
      $v = array_values( $keys );
      $s = sizeof( $v );
      for( $x = 0; $x < $s; $x++ )
      {
         $k = $v[ $x ];
         if ( $x == 0 )
         {
            if ( !array_key_exists( $k, $output ) )
               $output[ $k ] = array();
            $temp =& $output[ $k ];
         }
         if ( $x && ( $x + 1 ) !== $s )
         {
            if( !array_key_exists( $k, $temp ) )
               $temp[ $k ] = array();
            $temp =& $temp[$k];
         }
         if ( ( $x + 1 ) == $s )
            $temp[$k] = $value;
      }
   }

   $baz = array();
   foreach( $foo as $bar )
   {
      $this->convertAssociativeToMulti( $baz, $bar['keys'], $bar['values'] );
   }

那么,如何更简单地实现这个/重构我已有的内容呢?

1
+1 对于关于“复杂化手套”的链接! - cheesemacfly
看一下我在这个问题中的回答,我认为它们很相似。 - Barmar
@Barmar - 相似。我认为该解决方案缺乏维护我的用例中的适当层次结构。由于我循环遍历多个“keys”数组,使用您的代码它们都嵌套在最后一个集合下面。 - kmfk
是的,这就解释了为什么我的代码要短得多。它只处理一个条目,而不是像你的那样处理数组。 - Barmar
1个回答

3

这更简洁一些:

$result = [];
foreach($foo as $item)
{
    //Start at the outermost level of the result array
    $level = &$result;
    foreach($item['keys'] as $key)
    {
        //Add levels to the result array as needed
        if(!isset($level[$key])) $level[$key] = [];
        //Iterate to the next nested level
        $level = &$level[$key];
    }
    //Append values to the innermost level
    foreach($item['values'] as $k => $v) $level[$k] = $v;
}
//Don't keep a reference hanging around
unset($level);
var_dump($result);

很有意思。我之前尝试过使用array_merge,因为我认为这样会简化很多问题。但是我发现数字键可能会被改变,根据文档:具有数字键的输入数组中的值将在结果数组中重新编号,其递增键从零开始。 - kmfk
没事了,我懂了。谢谢,我已经用我的代码测试过了。无论如何,我都必须放弃array_merge,因为我的示例显示的是值数组,实际上它是一个对象——不管怎样,更加简洁。 - kmfk
哎呀,我忘记了array_merge。不过用一个简单的foreach很容易就能替代它。 - Jon Hulka
实际上,根据我在问题中提供的信息,您的array_merge是正确的,因为您只是将“values”合并到空数组中。当我之前尝试合并类似的键时,出现了问题。再次感谢。 - kmfk
1
@mickmackusa 我添加了一些注释,希望能够澄清正在发生的事情。我花了一些时间来弄清楚这个问题 - 这个答案是我10年前写的。 - Jon Hulka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接