如何在 PHP 中将多维数组“展平”为简单数组? [复制]
Posted
技术标签:
【中文标题】如何在 PHP 中将多维数组“展平”为简单数组? [复制]【英文标题】:How to "flatten" a multi-dimensional array to simple one in PHP? [duplicate] 【发布时间】:2010-10-06 07:24:03 【问题描述】:这可能是初学者的问题,但我已经阅读了较长时间的文档,但找不到任何解决方案。我想我可以对每个维度使用 implode,然后将这些字符串与 str_split
重新组合在一起以创建新的简单数组。但是我永远不知道连接模式是否也在值中,所以在执行str_split
之后,我的原始值可能会中断。
对于多维数组内部的数组,是否有类似combine($array1, $array2)
的东西?
【问题讨论】:
请查看此链接以获取解决方案:***.com/questions/14951811/… 另一个很好的参考问题也许有更好的答案:How to Flatten a Multidimensional Array? 【参考方案1】:对于 necrobumping 感到抱歉,但所提供的答案都没有达到我直观理解为“扁平化多维数组”的效果。即本案:
[
'a' => [
'b' => 'value',
]
]
所有提供的解决方案都会将其扁平化为 ['value']
,但这会丢失有关键和深度的信息,而且如果您在其他地方有另一个“b”键,它将覆盖它们。
我想得到这样的结果:
[
'a_b' => 'value',
]
array_walk_recursive
没有传递有关它当前递归的密钥的信息,所以我只是简单地递归:
function flatten($array, $prefix = '')
$return = [];
foreach ($array as $key => $value)
if (is_array($value))
$return = array_merge($return, flatten($value, $prefix . $key . '_'));
else
$return[$prefix . $key] = $value;
return $return;
根据自己的喜好修改 $prefix 和 '_' 分隔符。
这里是游乐场:https://3v4l.org/0B8hf
【讨论】:
【参考方案2】:有人可能会觉得这很有用,我在某个维度上展平数组时遇到了问题,我将其称为最后一维,例如,如果我有这样的数组:
array (
'germany' =>
array (
'cars' =>
array (
'bmw' =>
array (
0 => 'm4',
1 => 'x3',
2 => 'x8',
),
),
),
'france' =>
array (
'cars' =>
array (
'peugeot' =>
array (
0 => '206',
1 => '3008',
2 => '5008',
),
),
),
)
或者:
array (
'earth' =>
array (
'germany' =>
array (
'cars' =>
array (
'bmw' =>
array (
0 => 'm4',
1 => 'x3',
2 => 'x8',
),
),
),
),
'mars' =>
array (
'france' =>
array (
'cars' =>
array (
'peugeot' =>
array (
0 => '206',
1 => '3008',
2 => '5008',
),
),
),
),
)
当我调用下面的方法时,这两个数组都会得到结果:
array (
0 =>
array (
0 => 'm4',
1 => 'x3',
2 => 'x8',
),
1 =>
array (
0 => '206',
1 => '3008',
2 => '5008',
),
)
所以我正在展平到最后一个应该保持不变的数组维度,下面的方法可以重构为实际上停止在任何级别:
function flattenAggregatedArray($aggregatedArray)
$final = $lvls = [];
$counter = 1;
$lvls[$counter] = $aggregatedArray;
$elem = current($aggregatedArray);
while ($elem)
while(is_array($elem))
$counter++;
$lvls[$counter] = $elem;
$elem = current($elem);
$final[] = $lvls[$counter];
$elem = next($lvls[--$counter]);
while ( $elem == null)
if (isset($lvls[$counter-1]))
$elem = next($lvls[--$counter]);
else
return $final;
【讨论】:
【参考方案3】:我找到了一种将多级数组转换为一个的简单方法。 我使用函数“http_build_query”将数组转换为 url 字符串。 然后,用explode拆分字符串并解码值。
这是一个示例。
$converted = http_build_query($data);
$rows = explode('&', $converted);
$output = array();
foreach($rows AS $k => $v)
list($kk, $vv) = explode('=', $v);
$output[ urldecode($kk) ] = urldecode($vv);
return $output;
【讨论】:
【参考方案4】:如果您特别有一个不超过一级深度的数组(我认为常见的用例),您可以使用 array_merge
和 splat 运算符。
<?php
$notFlat = [[1,2],[3,4]];
$flat = array_merge(...$notFlat);
var_dump($flat);
输出:
array(4)
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
splat 运算符有效地将数组数组更改为数组列表作为array_merge
的参数。
【讨论】:
这对我来说似乎是最好的答案。它不适用于字符串键,但可以轻松修改为:$flat = array_merge( array_keys( $notFlat ), ...array_values( $notFlat ) );
【参考方案5】:
这是一条线,超级好用:
$result = array();
array_walk_recursive($original_array,function($v) use (&$result) $result[] = $v; );
在匿名函数/闭包内部很容易理解。 $v
是您的 $original_array
的值。
【讨论】:
这是唯一一个对我有用的两级数组。【参考方案6】:Use array_walk_recursive
<?php
$aNonFlat = array(
1,
2,
array(
3,
4,
5,
array(
6,
7
),
8,
9,
),
10,
11
);
$objTmp = (object) array('aFlat' => array());
array_walk_recursive($aNonFlat, create_function('&$v, $k, &$t', '$t->aFlat[] = $v;'), $objTmp);
var_dump($objTmp->aFlat);
/*
array(11)
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
[5]=>
int(6)
[6]=>
int(7)
[7]=>
int(8)
[8]=>
int(9)
[9]=>
int(10)
[10]=>
int(11)
*/
?>
使用 PHP 5.5.9-1ubuntu4.24 (cli) 测试(构建时间:2018 年 3 月 16 日 12:32:06)
【讨论】:
有谁知道为什么这不起作用,除非我使用(折旧的)调用时间通过引用。即 array_walk_recursive($array, create_function('&$v, $k, &$t', '$t[] = $v;'), &$flattened);函数定义正确定义为按引用传递。但除非我在通话期间通过引用传递,否则不起作用。 @jskilski 对象(在本例中为$objTmp
)通过引用自动传递;数组不是。尝试使用匿名函数 (php.net/manual/en/functions.anonymous.php) 而不是 create_function
。
由于 array_walk_recursive 中的错误,这在 php 5.3.3 中不起作用 - bugs.php.net/bug.php?id=52719
@crazyphoton 扭结还说This bug has been fixed in SVN.
为什么这个答案提到使用array_values()
?我根本看不到答案中涉及该功能的任何用途。【参考方案7】:
$array = your array
$result = call_user_func_array('array_merge', $array);
echo "<pre>";
print_r($result);
参考号:http://php.net/manual/en/function.call-user-func-array.php
这是另一种解决方案(适用于多维数组):
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);
【讨论】:
这个答案比接受的答案快得多。 从 php5.3 开始,您现在可以使用 splat 运算符:$result = array_merge(...$array);
php.net/manual/en/…
您的第一个答案不适用于多维数组。 3v4l.org/tY8vD【参考方案8】:
简单的方法..通过递归查看..
<?php
function flatten_array($simple)
static $outputs=array();
foreach ( $simple as $value)
if(is_array($value))
flatten_array($value);
else
$outputs[]=$value;
return $outputs;
$eg=['s'=>['p','n'=>['t']]];
$out=flatten_array($eg);
print_r($out);
?>
【讨论】:
为什么在这项任务中使用static
可能是个坏主意?意外的数据保留。如果他们不知道/不期望这种行为,这肯定会让程序员大吃一惊。 Look at this demonstration.
您发布了一个“仅代码”的答案——这些在 *** 上的价值很低,因为它们无法教育 OP 和未来的研究人员。请花一点时间来改进这个答案,包括您的答案是如何工作的,以及为什么您认为它比之前的答案更好。【参考方案9】:
如果您对丢失数组键没问题,您可以使用递归闭包作为利用 array_values() 的回调来展平多维数组,确保此回调是 array_walk() 的参数,如下所示。
<?php
$array = [1,2,3,[5,6,7]];
$nu_array = null;
$callback = function ( $item ) use(&$callback, &$nu_array)
if (!is_array($item))
$nu_array[] = $item;
else
if ( is_array( $item ) )
foreach( array_values($item) as $v)
if ( !(is_array($v)))
$nu_array[] = $v;
else
$callback( $v );
continue;
;
array_walk($array, $callback);
print_r($nu_array);
上一个示例的一个缺点是它所涉及的代码比以下使用 array_walk_recursive() 和简化回调的解决方案要多得多:
<?php
$array = [1,2,3,[5,6,7]];
$nu_array = [];
array_walk_recursive($array, function ( $item ) use(&$nu_array )
$nu_array[] = $item;
);
print_r($nu_array);
见live code
这个例子似乎比上一个更可取,隐藏了如何从多维数组中提取值的细节。当然,迭代会发生,但它是否需要递归或控制结构,只有通过阅读 array.c 才能知道。由于函数式编程关注的是输入和输出,而不是获得结果的细节,因此人们当然可以不关心幕后的迭代是如何发生的,直到有远见的雇主提出这样的问题。
【讨论】:
【参考方案10】:您可以使用Non-standard PHP library (NSPL) 中的flatten 函数。它适用于数组和任何可迭代的数据结构。
assert([1, 2, 3, 4, 5, 6, 7, 8, 9] === flatten([[1, [2, [3]]], [[[4, 5, 6]]], 7, 8, [9]]));
【讨论】:
【参考方案11】:使用高阶函数(注意:我使用的是inline anonymous functions,它出现在 PHP 5.3 中):
function array_flatten($array)
return array_reduce(
$array,
function($prev, $element)
if (!is_array($element))
$prev[] = $element;
else
$prev = array_merge($prev, array_flatten($element));
return $prev;
,
array()
);
【讨论】:
【参考方案12】:给定多维数组并将其转换为一维,可以通过取消设置所有具有数组的值并将它们保存到第一维来完成,例如:
function _flatten_array($arr)
while ($arr)
list($key, $value) = each($arr);
is_array($value) ? $arr = $value : $out[$key] = $value;
unset($arr[$key]);
return (array)$out;
【讨论】:
我对这个答案投了反对票,因为它不适用于任何版本。 3v4l.org/7cO9N(证明)另外,each()
已从 php7.2 中弃用。【参考方案13】:
这些对我都不起作用... 所以不得不自己运行它。 工作得很好:
function arrayFlat($arr)
$out = '';
foreach($arr as $key => $value)
if(!is_array($value))
$out .= $value.',';
else
$out .= $key.',';
$out .= arrayFlat($value);
return trim($out,',');
$result = explode(',',arrayFlat($yourArray));
echo '<pre>';
print_r($result);
echo '</pre>';
【讨论】:
此仅代码答案无法按预期工作。 3v4l.org/U3bfp 【参考方案14】:在 PHP 7 中,您可以使用生成器和生成器委托 (yield from
) 来展平数组:
function array_flatten_iterator (array $array)
foreach ($array as $value)
if (is_array($value))
yield from array_flatten_iterator($value);
else
yield $value;
function array_flatten (array $array)
return iterator_to_array(array_flatten_iterator($array), false);
例子:
$array = [
1,
2,
[
3,
4,
5,
[
6,
7
],
8,
9,
],
10,
11,
];
var_dump(array_flatten($array));
http://3v4l.org/RU30W
【讨论】:
【参考方案15】:如果您只对某个特定键的值感兴趣,您可能会发现这种方法很有用:
function valuelist($array, $array_column)
$return = array();
foreach($array AS $row)
$return[]=$row[$array_column];
;
return $return;
;
例子:
鉴于 $get_role_action=
array(3)
[0]=>
array(2)
["ACTION_CD"]=>
string(12) "ADD_DOCUMENT"
["ACTION_REASON"]=>
NULL
[1]=>
array(2)
["ACTION_CD"]=>
string(13) "LINK_DOCUMENT"
["ACTION_REASON"]=>
NULL
[2]=>
array(2)
["ACTION_CD"]=>
string(15) "UNLINK_DOCUMENT"
["ACTION_REASON"]=>
NULL
比$variables['role_action_list']=valuelist($get_role_action, 'ACTION_CD');
会导致:
$variables["role_action_list"]=>
array(3)
[0]=>
string(12) "ADD_DOCUMENT"
[1]=>
string(13) "LINK_DOCUMENT"
[2]=>
string(15) "UNLINK_DOCUMENT"
您可以从那里执行值查找,如下所示:
if( in_array('ADD_DOCUMENT', $variables['role_action_list']) )
//do something
;
【讨论】:
这是一个 PHP 仿制的同名 CFML 函数。 我投了反对票,因为这是对错误问题的正确答案。【参考方案16】:你可以试试这个:
function flat_an_array($a)
foreach($a as $i)
if(is_array($i))
if($na) $na = array_merge($na,flat_an_array($i));
else $na = flat_an_array($i);
else $na[] = $i;
return $na;
【讨论】:
【参考方案17】:/*consider $mArray as multidimensional array and $sArray as single dimensional array
this code will ignore the parent array
*/
function flatten_array2($mArray)
$sArray = array();
foreach ($mArray as $row)
if ( !(is_array($row)) )
if($sArray[] = $row)
else
$sArray = array_merge($sArray,flatten_array2($row));
return $sArray;
【讨论】:
【参考方案18】:基于上一个chaos提交的示例函数的新方法,修复了multiarrays中覆盖字符串键的bug:
# Flatten a multidimensional array to one dimension, optionally preserving keys.
# $array - the array to flatten
# $preserve_keys - 0 (default) to not preserve keys, 1 to preserve string keys only, 2 to preserve all keys
# $out - internal use argument for recursion
function flatten_array($array, $preserve_keys = 2, &$out = array(), &$last_subarray_found)
foreach($array as $key => $child)
if(is_array($child))
$last_subarray_found = $key;
$out = flatten_array($child, $preserve_keys, $out, $last_subarray_found);
elseif($preserve_keys + is_string($key) > 1)
if ($last_subarray_found)
$sfinal_key_value = $last_subarray_found . "_" . $key;
else
$sfinal_key_value = $key;
$out[$sfinal_key_value] = $child;
else
$out[] = $child;
return $out;
Example:
$newarraytest = array();
$last_subarray_found = "";
$this->flatten_array($array, 2, $newarraytest, $last_subarray_found);
【讨论】:
【参考方案19】:// $array = your multidimensional array
$flat_array = array();
foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $k=>$v)
$flat_array[$k] = $v;
还记录了: http://www.phpro.org/examples/Flatten-Array.html
【讨论】:
注意:仅用于基元数组。 “RecursiveArrayIterator 将所有对象视为有孩子,并尝试递归到它们中。” php.net/manual/en/class.recursivearrayiterator.php#106519 @hakre: +1 同意:在这个答案中添加iterator_to_array()
将否定foreach
循环的需要。它可以是一个简单的单行函数。 (虽然有点长的单行)
我知道这是旧的但仍然有用,但是 $k 需要替换为独特的东西,例如计数器。如果内部数组中的名称与主数组中的名称相同,则仅使用 $k 会导致元素被删除。【参考方案20】:
在 PHP>=5.3 中,根据 Luc M 的回答(第一个),您可以使用这样的闭包
array_walk_recursive($aNonFlat, function(&$v, $k, &$t)$t->aFlat[] = $v;, $objTmp);
我喜欢这个,因为我不必像使用 create_function() 时那样用引号将函数的代码括起来
【讨论】:
如果你使用匿名函数,你还不如直接使用捕获的闭包变量而不是objTemp
这个东西
PHP5.3.3 中有一个错误会导致崩溃 - bugs.php.net/bug.php?id=52719【参考方案21】:
来自 PHP 的 user comments(简体)和 here 的另一种方法:
function array_flatten_recursive($array)
if (!$array) return false;
$flat = array();
$RII = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
foreach ($RII as $value) $flat[] = $value;
return $flat;
这种方法的最大好处是它可以跟踪递归的深度,如果您在展平时需要它。 这将输出:
$array = array(
'A' => array('B' => array( 1, 2, 3)),
'C' => array(4, 5)
);
print_r(array_flatten_recursive($array));
#Returns:
Array (
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
)
【讨论】:
注意:仅用于基元数组。 “RecursiveArrayIterator 将所有对象视为有孩子,并尝试递归到它们中。” php.net/manual/en/class.recursivearrayiterator.php#106519【参考方案22】:function flatten_array($array, $preserve_keys = 0, &$out = array())
# Flatten a multidimensional array to one dimension, optionally preserving keys.
#
# $array - the array to flatten
# $preserve_keys - 0 (default) to not preserve keys, 1 to preserve string keys only, 2 to preserve all keys
# $out - internal use argument for recursion
foreach($array as $key => $child)
if(is_array($child))
$out = flatten_array($child, $preserve_keys, $out);
elseif($preserve_keys + is_string($key) > 1)
$out[$key] = $child;
else
$out[] = $child;
return $out;
【讨论】:
抱歉,它似乎无法正确处理多维数组 - Demo【参考方案23】:非递归解决方案(但破坏顺序):
function flatten($ar)
$toflat = array($ar);
$res = array();
while (($r = array_shift($toflat)) !== NULL)
foreach ($r as $v)
if (is_array($v))
$toflat[] = $v;
else
$res[] = $v;
return $res;
【讨论】:
以上是关于如何在 PHP 中将多维数组“展平”为简单数组? [复制]的主要内容,如果未能解决你的问题,请参考以下文章