有很多使用点表示法访问 PHP 数组的技巧和代码示例,但我想做一些相反的事情。我想采用这样的多维数组:
$myArray = array(
'key1' => 'value1',
'key2' => array(
'subkey' => 'subkeyval'
),
'key3' => 'value3',
'key4' => array(
'subkey4' => array(
'subsubkey4' => 'subsubkeyval4',
'subsubkey5' => 'subsubkeyval5',
),
'subkey5' => 'subkeyval5'
)
);
并将其变成这样(可能通过一些递归函数):
$newArray = array(
'key1' => 'value1',
'key2.subkey' => 'subkeyval',
'key3' => 'value3',
'key4.subkey4.subsubkey4' => 'subsubkeyval4',
'key4.subkey5.subsubkey5' => 'subsubkeyval5',
'key4.subkey5' => 'subkeyval5'
);
代码
$ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($myArray));
$result = array();
foreach ($ritit as $leafValue) {
$keys = array();
foreach (range(0, $ritit->getDepth()) as $depth) {
$keys[] = $ritit->getSubIterator($depth)->key();
}
$result[ join('.', $keys) ] = $leafValue;
}
输出
Array
(
[key1] => value1
[key2.subkey] => subkeyval
[key3] => value3
[key4.subkey4.subsubkey4] => subsubkeyval4
[key4.subkey4.subsubkey5] => subsubkeyval5
[key4.subkey5] => subkeyval5
)
演示:http://codepad.org/YiygqxTM
我得走了,但如果你明天需要解释,请问我。
RecursiveIteratorIterator
。但这里有一个更优化的解决方案,避免使用嵌套循环:
$iterator = new RecursiveIteratorIterator(
new RecursiveArrayIterator($arr),
RecursiveIteratorIterator::SELF_FIRST
);
$path = [];
$flatArray = [];
foreach ($iterator as $key => $value) {
$path[$iterator->getDepth()] = $key;
if (!is_array($value)) {
$flatArray[
implode('.', array_slice($path, 0, $iterator->getDepth() + 1))
] = $value;
}
}
这里有几点需要说明。请注意此处使用
RecursiveIteratorIterator::SELF_FIRST
常量。这很重要,因为默认值是 RecursiveIteratorIterator::LEAVES_ONLY
,它不会让我们访问所有密钥。因此,通过这个常量集,我们从数组的顶层开始并深入。这种方法让我们可以存储密钥的历史记录,并在使用 RecursiveIteratorIterator::getDepth
方法丰富叶子时准备密钥。
这是我对递归解决方案的看法,适用于任何深度的数组:
function convertArray($arr, $narr = array(), $nkey = '') {
foreach ($arr as $key => $value) {
if (is_array($value)) {
$narr = array_merge($narr, convertArray($value, $narr, $nkey . $key . '.'));
} else {
$narr[$nkey . $key] = $value;
}
}
return $narr;
}
可以称为
$newArray = convertArray($myArray)
。
这是与上面的 Blafrat 类似的另一种方法 - 但将数组简单地处理为值。
function dot_flatten($input_arr, $return_arr = array(), $prev_key = '')
{
foreach ($input_arr as $key => $value)
{
$new_key = $prev_key . $key;
// check if it's associative array 99% good
if (is_array($value) && key($value) !==0 && key($value) !==null)
{
$return_arr = array_merge($return_arr, dot_flatten($value, $return_arr, $new_key . '.'));
}
else
{
$return_arr[$new_key] = $value;
}
}
return $return_arr;
}
(唯一无法捕获的情况是你有一个关联的值,但第一个键是 0。)
请注意,RecursiveIteratorIterator 可能比常规递归函数慢。 https://xenforo.com/community/threads/php-spl-why-is-recursiveiteratoriterator-100x-slower-than-recursive-search.57572/
在本例中,使用 php5.6 给出的 1000 次迭代的示例数组,该代码的速度是原来的两倍(递归 = .032 与 interator = .062) - 但对于大多数情况来说,差异可能微不足道。主要是我更喜欢递归,因为我发现迭代器的逻辑对于像这样的简单用例来说不必要地复杂。