如何在不循环的情况下展平一个简单的数组?
Posted
技术标签:
【中文标题】如何在不循环的情况下展平一个简单的数组?【英文标题】:How can I flatten a simple array without looping? 【发布时间】:2013-02-03 08:45:18 【问题描述】:我想把一个简单的多维数组变成一个更简单的数组。
转动这个:
Array
(
[0] => Array
(
[id] => 123
)
[1] => Array
(
[id] => 456
)
...
[999] => Array
(
[id] => 789
)
)
到这样的数组中:
Array
(
[0] => 123
[1] => 456
...
[999] => 789
)
我想这样做不循环使用foreach
。这在 php 中可行吗?
这是我已经可以使用foreach
循环解决它的方法:
$newArr = array();
foreach ($arr as $a)
$newArr[] = $a['id'];
$arr = $newArr;
我想不循环。你能帮忙吗?
【问题讨论】:
为什么不循环播放? 避免基于“前提”的标准做法是无效的 O(n) 循环是 PHP 开发人员最不必担心的问题 @Ryan 你基本上保证没有人能一眼看懂你的代码。 展望未来,PHP 可能有一个array_column()
函数(虽然可能不在 PHP 5.5.0 中)。 $ids = array_column($array, 'id');
【参考方案1】:
我很欣赏您希望拥有接近函数式编程和隐式循环的东西,但 PHP 不适合您。它不会以实用的风格自然地表达自己。
reset
函数返回数组中的第一个元素,因此您可以将该函数映射到数组:
array_map('reset', $array)
然而在 PHP 中最快的方法是一个简单的for
循环(不是foreach
,for
)。这里有一堆不同的扁平化方法。只有包含for
和foreach
的函数会执行显式循环并包含在比较中。
function flatten_for($arr)
$c = count($arr);
$newarr = array();
for ($i = 0; $i < $c; $i++)
$newarr[] = $arr[$i][0];
return $newarr;
function flatten_for_inplace($arr)
$c = count($arr);
for ($i = 0; $i < $c; $i++)
$arr[$i] = $arr[$i][0];
function flatten_foreach($arr)
$newarr = array();
foreach ($arr as $value)
$newarr[] = $value[0];
return $newarr;
function flatten_foreach_inplace($arr)
foreach ($arr as $k => $v)
$arr[$k] = $v[0];
function flatten_foreach_inplace_ref($arr)
foreach ($arr as &$value)
$value = $value[0];
function flatten_map($arr)
return array_map('reset', $arr);
function flatten_walk($arr)
array_walk($arr, function(&$v, $k)$v = $v[0];);
function visitor($v, $k, &$a)
return $a[] = $v;
function flatten_walk_recursive($arr)
$newarr = array();
array_walk_recursive($arr, 'visitor', $newarr);
return $newarr;
function reducer($result, $item)
return $item[0];
function flatten_reduce($arr)
return array_reduce($arr, 'reducer', array());
function flatten_merge($arr)
return call_user_func_array('array_merge_recursive', $arr);
这是计时码:
function buildarray($length)
return array_map(function($e)return array($e);, range(0, $length));
function timeit($callable, $argfactory, $iterations)
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++)
call_user_func($callable, call_user_func($argfactory));
return microtime(true) - $start;
function time_callbacks($callbacks, $argfactory, $iterations)
$times = array();
foreach ($callbacks as $callback)
$times[$callback] = timeit($callback, $argfactory, $iterations);
return $times;
function argfactory()
return buildarray(1000);
$flatteners = array(
'flatten_for', 'flatten_for_inplace', 'flatten_foreach',
'flatten_foreach_inplace', 'flatten_foreach_inplace_ref',
'flatten_map', 'flatten_walk', 'flatten_walk_recursive',
'flatten_reduce', 'flatten_merge',
);
$results = time_callbacks($flatteners, 'argfactory', 1000);
var_export($results);
在较旧的 MacBook Pro(Core 2 Duo、2.66 GHz、8GB、PHP 5.3.15 和 Suhosin-Patch)上,我得到以下结果:
array (
'flatten_for' => 12.793387174606,
'flatten_for_inplace' => 14.093497991562,
'flatten_foreach' => 16.71691608429,
'flatten_foreach_inplace' => 16.964510917664,
'flatten_foreach_inplace_ref' => 16.618073940277,
'flatten_map' => 24.578175067902,
'flatten_walk' => 22.884744882584,
'flatten_walk_recursive' => 31.647840976715,
'flatten_reduce' => 17.748590946198,
'flatten_merge' => 20.691106081009,
)
for
和 foreach
方法之间的差异在较长的数组上更小。
令人惊讶的是(对我来说,无论如何)flatten_merge
仍然比普通的 for
循环慢。我预计 array_merge_recursive
至少会更快,因为它基本上将整个工作交给了 C 函数!
【讨论】:
如果您担心内部数组指针的状态,可以只使用reset
而不是current
。
令人着迷。这非常有帮助。这个答案需要更多的支持!我期待很快在我自己的盒子上进行测试。
I admire your desire to have something approaching functional programming and implicit looping, but PHP is the wrong language for you.
不幸的是,即使在 2021 年它仍然是真的......【参考方案2】:
你可以map
它:
$arr = array_map(function($element)
return $element['id'];
, $arr);
由于array_map
可能在内部循环,您可以真正做到不循环:
$arr = array_reduce($arr, function($arr, $element)
$arr[] = $element['id'];
return $arr;
);
但没有理由不循环。没有真正的性能提升,而且代码的可读性可能会降低。
【讨论】:
@Dagonarray_reduce
也循环吗?
那么第二句话是假的?【参考方案3】:
目前,最简单的方法是使用 array_column() 函数
$newArray = array_column($array, 'id');
【讨论】:
以上是关于如何在不循环的情况下展平一个简单的数组?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用 numpy 的情况下将 2D 列表展平为 1D? [复制]