带有array_filter的PHP array_column

时间:2017-07-28 08:04:48

标签: php arrays min

我这样做是为了回应数组中的最小值......

library(stringr)
str_pad(foo, width = 10, pad = "0")
#[1] "0000000000" "000000999G" "0123456789" "0123456789" "000000000S"

现在我想从结果中排除0,我知道我可以使用array_filter来实现这一点但是我需要处理数组两次吗?

6 个答案:

答案 0 :(得分:3)

是的,这样做:

$min = min(array_filter(array_column($array, 'a')));

它会迭代数组三次,每个函数一次。

您可以使用array_reduce在一次迭代中执行此操作:

$min = array_reduce($array, function ($min, $val) {
    return $min === null || ($val['a'] && $val['a'] < $min) ? $val['a'] : $min;
});

是否更快还是必须进行基准测试,PHP回调函数可能比C中的三个函数慢。

在没有函数调用开销的情况下,一个更有效的解决方案将是一个很好的循环:

$min = null;
foreach ($array as $val) {
    if ($min === null || ($val['a'] && $val['a'] < $min)) {
        $min = $val['a'];
    }
}

最后,您需要进行基准测试并确定性能与可读性的正确权衡。在实践中,除非你有积极的数据集,否则第一个单行可能会做得很好。

答案 1 :(得分:2)

使用array_reduce()仅一次遍历数组的解决方案。

$min = array_reduce(
    $array,
    function($acc, array $item) {
        return min($acc, $item['a'] ?: INF);
    },
    INF
);

工作原理:

+INF作为部分最小值开头。它在阵列中遇到的所有值理论上都比这小。

回调函数忽略具有0(或其他值等于FALSE when evaluated as boolean)的项目。表达式$item['a'] ?: INF使用INF(无穷大)代替$item['a'],以避免更改部分结果(忽略0值)。

它返回当前部分最小值(在参数array_reduce()中通过$acc)与当前项的值之间的最小值,如上所述。

$min中的值是FALSE中项目的a列中不$array - ey值的最小值。如果所有这些值均为0FALSE),则$min中返回的值为INF

答案 2 :(得分:1)

您可以使用sort

$array = [
[
'a' => 0,
'f' => 0,
'f' => 0,
'l' => 61.60
],
[
'a' => 38,
'f' => 0,
'f' => 0,
'l' => 11.99
],
[
'a' => 28,
'f' => 0,
'f' => 0,
'l' => 3.40
 ]
];

$array = array_column($array, 'a');

sort($array);

echo $array[1];

答案 3 :(得分:1)

尝试使用array_flipunset() php函数
 像这样

  $array = [
[
    'a' => 0,
    'f' => 0,
    'f' => 0,
    'l' => 61.60
],
[
    'a' => 38,
    'f' => 0,
    'f' => 0,
    'l' => 11.99
],
[
    'a' => 28,
    'f' => 0,
    'f' => 0,
    'l' => 3.40
 ]
];
$min = array_flip(array_column($array, 'a'));
unset($min[0]);
$min=min(array_flip($min));

o / p

   28    

答案 4 :(得分:1)

这不是答案,但评论无法提供其内容的格式。它也不能留在my answer,因为它在技术上不属于它。

我为@deceze和three solutions 提供的my solution生成了基准,并使用PHP 7.0运行它。以下所有内容仅适用于PHP 7.x。

PHP 5运行得慢得多,需要更多内存。

我首先在1,000,000项的小列表上运行代码100,然后迭代地将迭代次数除以10,同时将列表长度乘以10 }。

结果如下:

$ php bench.php 100 1000000
Generating 100 elements... Done. Time: 0.000112 seconds.
array_filter(): 3.265538 seconds/1000000 iterations. 0.000003 seconds/iteration.
foreach       : 3.771463 seconds/1000000 iterations. 0.000004 seconds/iteration.
reduce @deceze: 6.869162 seconds/1000000 iterations. 0.000007 seconds/iteration.
reduce @axiac : 8.599051 seconds/1000000 iterations. 0.000009 seconds/iteration.

$ php bench.php 1000 100000
Generating 1000 elements... Done. Time: 0.000750 seconds.
array_filter(): 3.024423 seconds/100000 iterations. 0.000030 seconds/iteration.
foreach       : 3.997505 seconds/100000 iterations. 0.000040 seconds/iteration.
reduce @deceze: 6.669426 seconds/100000 iterations. 0.000067 seconds/iteration.
reduce @axiac : 8.342756 seconds/100000 iterations. 0.000083 seconds/iteration.

$ php bench.php 10000 10000
Generating 10000 elements... Done. Time: 0.002643 seconds.
array_filter(): 2.913948 seconds/10000 iterations. 0.000291 seconds/iteration.
foreach       : 4.190049 seconds/10000 iterations. 0.000419 seconds/iteration.
reduce @deceze: 9.649768 seconds/10000 iterations. 0.000965 seconds/iteration.
reduce @axiac : 11.236113 seconds/10000 iterations. 0.001124 seconds/iteration.

$ php bench.php 100000 1000
Generating 100000 elements... Done. Time: 0.042237 seconds.
array_filter(): 90.369577 seconds/1000 iterations. 0.090370 seconds/iteration.
foreach       : 15.487466 seconds/1000 iterations. 0.015487 seconds/iteration.
reduce @deceze: 19.896064 seconds/1000 iterations. 0.019896 seconds/iteration.
reduce @axiac : 15.056250 seconds/1000 iterations. 0.015056 seconds/iteration.

对于最多约10,000个元素的列表,结果是一致的,并且符合预期:array_filter()最快,foreach接近array_reduce()解决方案对齐通过他们调用的函数数量(@ deceze的速度更快,因为它不调用任何函数,我的调用min()一次)。即使总运行时间也一致。

列表中90项的array_filter()解决方案的100,000秒值看起来不合适,但它有一个简单的解释:array_filter()和{{ 1}}生成新数组。它们分配内存并复制数据,这需要时间。添加垃圾收集器所需的时间,以释放array_column()小数组列表使用的所有小内存块,并且运行时间会更快。

10,000项数组的另一个有趣结果是使用100,000的{​​{3}}与array_reduce()解决方案一样快,并且优于使用foreach的@ deceze解决方案。我对这个结果没有解释。

当这些事情开始发生时,我试图找出一些门槛。为此,我使用不同的列表大小运行基准,从array_reduce()开始,并将大小增加5,000,同时将访问项的总数保持为1,000。结果可以找到my solution

结果令人惊讶。对于列表的某些大小(100,000,0008,00011,00012,00013,000项目),17,000解决方案需要比使用array_filter()的任何解决方案完成大约10倍的时间。但是,对于其他列表大小,它会返回到轨道并在大约3秒内完成1亿个节点访问,而其他解决方案所需的时间会随着列表长度的增加而不断增加。

我怀疑array_reduce()解决方案所需时间内跳跃的罪魁祸首是PHP的内存分配策略。对于初始数组的某些长度,array_filter()array_column()返回的临时数组可能会触发比其他大小更多的内存分配和垃圾清理周期。当然,有可能在我没有测试的其他尺寸上发生相同的行为。

在列表中的array_filter()个项目周围,我的解决方案使用16,000...17,000开始比@ deceze的解决方案运行得更快,并且在array_reduce()周围开始执行与25.000解决方案同样快的速度(有时甚至更快)。

对于长度超过foreach - 16,000项的列表,17,000解决方案始终需要比其他解决方案更长的时间。

可以找到基准代码here。不幸的是,对于大于array_filter()个元素的列表,它不能在3v4l.org上执行,因为它达到了系统强加的内存限制。

可以找到大于15,000项的列表的结果here

代码是在Linux Mint 18.1上使用5,000 CLI执行的。没有涉及APC或其他类型的缓存。

结论

对于小型列表,最多PHP 7.0.20项,请使用5,000解决方案,因为它对此列表的大小表现良好,看起来很整洁。

对于大于array_filter(array_column())项的列表,请切换到5,000解决方案。它看起来不太好,但运行速度很快,不需要额外的内存。随着列表大小的增加,坚持下去。

对于hackatons,采访以及对同事看起来很聪明,请使用任何foreach解决方案。它显示了您对here的了解以及您对PHP array functions编程概念的理解。

答案 5 :(得分:-1)

为什么你不尝试这样?

foreach($array as &$value) {
    $value = array_filter($value, function($v) {    return  $value !=0 });
}

Havnt测试!!!