在PHP中,是否有可能在不使用递归或引用的情况下将(双/多)维数组展开?
我只对值感兴趣,可以忽略键,我考虑使用array_map()
和array_values()
来实现。
在PHP中,是否有可能在不使用递归或引用的情况下将(双/多)维数组展开?
我只对值感兴趣,可以忽略键,我考虑使用array_map()
和array_values()
来实现。
在下面的答案中可以找到一个更近期的解决方案。
从PHP 5.3开始,最简短的解决方案似乎是使用新的闭包语法array_walk_recursive()
:
function flatten(array $array) {
$return = array();
array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
return $return;
}
function flatten(array $array) {
$return = array();
array_walk_recursive($array, function($a,$b) use (&$return) { $return[$b] = $a; });
return $return;
}
- Brendon-Van-Heyzenarray_walk_recursive
与可选的$userdata
参数一起正常工作,因为它不接受引用。 - Tim Seguine$a = array(1,2,array(3,4, array(5,6,7), 8), 9);
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($a));
foreach($it as $v) {
echo $v, " ";
}
打印
1 2 3 4 5 6 7 8 9
iterator_to_array($it, false)
可以避免使用 foreach 循环。 - Alix Axelfunction flatten($arr){ $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr)); return iterator_to_array($it, true); }
希望这对其他人有所帮助。 - Mike S....
运算符展开外部数组后,使用array_merge
来展平二维数组。这段代码简单明了。array_merge(...$a);
这也适用于关联数组的集合。
$a = [[10, 20], [30, 40]];
$b = [["x" => "A", "y" => "B"], ["y" => "C", "z" => "D"]];
print_r(array_merge(...$a));
print_r(array_merge(...$b));
Array
(
[0] => 10
[1] => 20
[2] => 30
[3] => 40
)
Array
(
[x] => A
[y] => C
[z] => D
)
array_values
。$c = ["a" => ["x" => "A", "y" => "B"], "b" => ["y" => "C", "z" => "D"]];
print_r(array_merge(...array_values($c)));
Array
(
[x] => A
[y] => C
[z] => D
)
更新:根据 @MohamedGharib 的评论(适用于 PHP 7.3.x 及更早版本 ref)
如果外部数组为空,则此操作将抛出错误,因为 array_merge
将被调用零个参数。可以通过将空数组作为第一个参数添加来避免此错误。
array_merge([], ...$a);
array_merge([], ...$a);
。 - Mohamed Gharib$a = array_merge( array(), ...array_values( $a ) );
对我来说很有效,可用于展平使用 $wpdb->get_results( $sql, ARRAY_N )
查询 WordPress 中的单列结果。 - squarecandy解决二维数组问题的方案
请尝试以下方法:
$array = your array
$result = call_user_func_array('array_merge', $array);
echo "<pre>";
print_r($result);
编辑:21-Aug-13
这是适用于多维数组的解决方案:
function array_flatten($array) {
$return = array();
foreach ($array as $key => $value) {
if (is_array($value)){
$return = array_merge($return, array_flatten($value));
} else {
$return[$key] = $value;
}
}
return $return;
}
$array = Your array
$result = array_flatten($array);
echo "<pre>";
print_r($result);
参考:http://php.net/manual/zh/function.call-user-func-array.php
call_user_func_array('array_merge', [])
(注意空数组)返回 null 并触发 PHP 警告错误。如果你确定数组不会为空,那么这是一个巧妙的解决方案,但这并不是许多人可以做出的普遍假设。 - goat如果您想要不使用递归进行平铺,可以使用栈。当然,您可以将其放入自己的函数中,例如array_flatten
。以下是一种不使用键的版本:
function array_flatten(array $array)
{
$flat = array(); // initialize return array
$stack = array_values($array); // initialize stack
while($stack) // process stack until done
{
$value = array_shift($stack);
if (is_array($value)) // a value to further process
{
array_unshift($stack, ...$value);
}
else // a value to take
{
$flat[] = $value;
}
}
return $flat;
}
元素按照它们的顺序进行处理。因为子元素将被移动到堆栈的顶部,所以它们将被下一步处理。
也可以考虑将键值考虑在内,但是您需要使用不同的策略来处理堆栈。这是必要的,因为您需要处理子数组中可能存在的重复键。相关问题中有一个类似的答案:PHP Walk through multidimensional array while preserving keys
我不确定,但我曾经测试过这个:RecurisiveIterator确实使用递归,所以这取决于您实际需要什么。也应该可以基于堆栈创建递归迭代器:
foreach(new FlatRecursiveArrayIterator($array) as $key => $value)
{
echo "** ($key) $value\n";
}
我还没有实现基于RecursiveIterator
的堆栈,我认为这是一个好主意。
if(!empty($value)){$flat[] = $value}
以防止空值被添加到结果数组中。这个函数真是太棒了! - Alex Sarnowski$stack = array_merge(array_values($value), $stack);
简化为array_unshift($stack, ...$value);
,对于大多数情况而言,array_values()
调用可能是多余的,但由于该答案早于v5.6,因此不应进行编辑。 - Walf简明扼要的回答。
function flatten_array(array $array)
{
return iterator_to_array(
new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array)));
}
用法:
$array = [
'name' => 'Allen Linatoc',
'profile' => [
'age' => 21,
'favourite_games' => [ 'Call of Duty', 'Titanfall', 'Far Cry' ]
]
];
print_r( flatten_array($array) );
输出(在 PsySH 中):
Array
(
[name] => Allen Linatoc
[age] => 21
[0] => Call of Duty
[1] => Titanfall
[2] => Far Cry
)
现在你该如何处理这些键完全取决于你自己。干杯。
编辑(2017-03-01)
引用Nigel Alderton的担忧/问题:
仅作澄清,此方法保留键(包括数字键),因此具有相同键的值将会被覆盖。例如,
$array = ['a',['b','c']]
变成了Array([0] => b, [1] => c )
。因为'b'也具有键0
,所以'a'被覆盖了。
引用Svish的回答:
只需将iterator_to_array调用的第二个参数(
$use_keys
)设置为false即可。
$array = ['a',['b','c']]
将变成 Array ([0] => b, [1] => c )
。因为 'b'
也有一个键为 0
,所以 'a'
就被丢失了。 - Nigel Aldertoniterator_to_array($it, false);
时要小心!如果未设置此参数或将其设置为 TRUE,则会覆盖重复的键!!!如果您将其与 array(1,2,array(3,4, array(5,6,7), 8), 9);
一起使用,这将返回 5 6 7 9 而不是预期的 1 2 3 4 5 6 7 8 9。 - ponsfrilus我只是想指出这是一个折叠操作,所以可以使用array_reduce函数:
array_reduce($my_array, 'array_merge', array());
编辑:请注意,这可以用于展开任意层级。我们可以通过多种方式来做到这一点:
// Reduces one level
$concat = function($x) { return array_reduce($x, 'array_merge', array()); };
// We can compose $concat with itself $n times, then apply it to $x
// This can overflow the stack for large $n
$compose = function($f, $g) {
return function($x) use ($f, $g) { return $f($g($x)); };
};
$identity = function($x) { return $x; };
$flattenA = function($n) use ($compose, $identity, $concat) {
return function($x) use ($compose, $identity, $concat, $n) {
return ($n === 0)? $x
: call_user_func(array_reduce(array_fill(0, $n, $concat),
$compose,
$identity),
$x);
};
};
// We can iteratively apply $concat to $x, $n times
$uncurriedFlip = function($f) {
return function($a, $b) use ($f) {
return $f($b, $a);
};
};
$iterate = function($f) use ($uncurriedFlip) {
return function($n) use ($uncurriedFlip, $f) {
return function($x) use ($uncurriedFlip, $f, $n) {
return ($n === 0)? $x
: array_reduce(array_fill(0, $n, $f),
$uncurriedFlip('call_user_func'),
$x);
}; };
};
$flattenB = $iterate($concat);
// Example usage:
$apply = function($f, $x) {
return $f($x);
};
$curriedFlip = function($f) {
return function($a) use ($f) {
return function($b) use ($f, $a) {
return $f($b, $a);
}; };
};
var_dump(
array_map(
call_user_func($curriedFlip($apply),
array(array(array('A', 'B', 'C'),
array('D')),
array(array(),
array('E')))),
array($flattenA(2), $flattenB(2))));
当然,我们也可以使用循环,但问题要求使用类似于array_map或array_values的组合函数。
$concat
,我认为你应该只称其为 $flatten
。array_merge
是 php
中 concat 的等效函数。我曾经尝试过将 array_concat
添加为 array_merge
的别名,具体请见 这里。 - icc97使用递归。 希望通过看到它并不复杂,您对递归的恐惧会消散。
function flatten($array) {
if (!is_array($array)) {
// nothing to do if it's not an array
return array($array);
}
$result = array();
foreach ($array as $value) {
// explode the sub-array, and add the parts
$result = array_merge($result, flatten($value));
}
return $result;
}
$arr = array('foo', array('nobody', 'expects', array('another', 'level'), 'the', 'Spanish', 'Inquisition'), 'bar');
echo '<ul>';
foreach (flatten($arr) as $value) {
echo '<li>', $value, '</li>';
}
echo '<ul>';
输出:
<ul><li>foo</li><li>nobody</li><li>expects</li><li>another</li><li>level</li><li>the</li><li>Spanish</li><li>Inquisition</li><li>bar</li><ul>
只对二维数组进行扁平化:
$arr = [1, 2, [3, 4]];
$arr = array_reduce($arr, function ($a, $b) {
return array_merge($a, (array) $b);
}, []);
// Result: [1, 2, 3, 4]
$flatArr = array_merge(...$originalArray);
$flatArr = array_merge(...array_values($originalArray));
- Alliswell