从 php 中的数组生成多维数组?

Generate multi-dimensional array from an array in php?

我有一个关联数组列表如下:

[
"country" => "AU",
"state" => "VIC",
"suburb" => "Carlton",
"precedence" => ["country", "state", "suburb"]
]

我想要一个新的多维数组,如下所示,其中元素根据第一个数组上的 precedence 键定义的顺序嵌套:

[
 "country" => [
  "AU" => [
    "state" => [
      "VIC" => [
        "suburb" => "Carlton
      ]
     ]
    ]
   ]
]

以上只是一个示例,我想要一个适用于任何类型数组的通用解决方案。所有输入数组都满足的唯一条件是它们将具有 precedence 元素,表示需要生成输出数组的顺序。

我已经尝试了一些递归解决方案,但它没有按预期工作,我遇到了 PHP 致命错误:允许的 1073741824 字节内存大小已耗尽(看起来是 运行 无限):

function generateArray(&$array)
    {
        foreach ($array['precedence'] as $key => $property) {
            if ($key == sizeof($array['precedence']) - 1) {
                return [$property => $array[$property]];
            } else {
                return generateAssetConfig($array);
            }
        }
    }

试试这个:

function generateNestedArray($arr) {
  $precedence = $arr['precedence'];
  $nestedArray = [];
  for ($i = count($precedence)-1; $i >= 0; $i--) {
    $key = $precedence[$i];
    if (!$nestedArray) {
      $nestedArray[$key] = $arr[$key];
    } else {
      $nestedArray = [$key => [ $arr[$key]=> $nestedArray]];
    }
  } 
  
  return $nestedArray;
}

最简单的解决方案(递归函数):

function generateArrayRecursion($array, $precedenceIndex = 0) {
    $precedence = $array['precedence'];
    
    return [
        $precedence[$precedenceIndex] => $precedenceIndex === \count($precedence) - 1
            ? $array[$precedence[$precedenceIndex]]
            : [$array[$precedence[$precedenceIndex]] => generateArrayRecursion($array, $precedenceIndex + 1)]
    ];
}

备选方案(循环和数组引用):

function generateArray($array) {
    $precedence = $array['precedence'];
    $result = [];
    $lastKey = $precedence[count($precedence) - 1];

    $currentElement = &$result;
    foreach ($precedence as $key) {
        if ($key === $lastKey) {
            $currentElement[$key] = $array[$key];
        } else {
            $currentElement[$key] = [$array[$key] => []];
            $currentElement = &$currentElement[$key][$array[$key]];
        }
    }
    
    return $result;
}

用法示例:

$array = [
    "country" => "AU",
    "state" => "VIC",
    "suburb" => "Carlton",
    "precedence" => ["country", "state", "suburb"]
];

var_dump(generateArrayRecursion($array));
var_dump(generateArray($array));

这是执行此操作的递归算法:

<?php

$raw = [
    [
        "country" => "AU",
        "state" => "VIC",
        "suburb" => "Carlton",
        "precedence" => ["country", "state", "suburb"]
    ],
    [
        "country" => "AU",
        "state" => "NSW",
        "suburb" => "Sydney",
        "precedence" => ["country", "state", "suburb"]
    ]
];

function generateFromPrecedence($array)
{
    if (!isset($array['precedence']))
        throw new Exception('Precedence array does not exist');

    if (!empty(array_diff($array['precedence'], array_diff(array_keys($array), ['precedence']))))
        throw new Exception('Keys and precendence keys different');

    return generateStructure($array);
}

function generateStructure($array, $precedence = 0)
{
    if ($precedence == count($array['precedence'])-1)
        return [$array['precedence'][$precedence] => $array[$array['precedence'][$precedence]]];

    return [$array['precedence'][$precedence] => [$array[$array['precedence'][$precedence]] => generateStructure($array, ++$precedence)]];
}

$output = generateFromPrecedence($raw[0]);

var_dump($output);

输出:

array(1) {
["country"]=>
array(1) {
    ["AU"]=>
    array(1) {
    ["state"]=>
    array(1) {
        ["NSW"]=>
        array(1) {
        ["suburb"]=>
        string(6) "Sydney"
        }
    }
    }
}
}

你可以循环前面部分的反转项。

如果结果数组中还没有项目,添加第一个键=>值对。

Else 将当前结果包装在一个多维数组中,将迭代的当前值设置为外键,并将该值(对于源数组中的该键)与当前结果一起包装在第二个数组中。

$source = [
    "country" => "AU",
    "state" => "VIC",
    "suburb" => "Carlton",
    "precedence" => ["country", "state", "suburb"]
];

function generateArray($array)
{
    $result = [];
    foreach(array_reverse($array["precedence"]) as $v) {
        $result =! $result ? [$v => $array[$v]] : [$v => [$array[$v] => $result]];
    }
    return $result;
}

var_export(generateArray($source));

输出

array (
  'country' => 
  array (
    'AU' => 
    array (
      'state' => 
      array (
        'VIC' => 
        array (
          'suburb' => 'Carlton',
        ),
      ),
    ),
  ),
)