【问题标题】:Is there a PHP equivalent of JavaScript's Array.prototype.some() function是否有与 JavaScript 的 Array.prototype.some() 函数等效的 PHP
【发布时间】:2017-02-14 00:00:32
【问题描述】:

在 JavaScript 中,我们可以这样做:

function isBiggerThan10(element, index, array) {
  return element > 10;
}
[2, 5, 8, 1, 4].some(isBiggerThan10);  // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some

是否有 PHP 等效的 some() 函数?

【问题讨论】:

标签: javascript php functional-programming


【解决方案1】:

它不包括在内,但它们很容易创建。这使用了SRFI-1 名称anyevery,但可以重命名为someall

function array_any(array $array, callable $fn) {
    foreach ($array as $value) {
        if($fn($value)) {
            return true;
        }
    }
    return false;
}

function array_every(array $array, callable $fn) {
    foreach ($array as $value) {
        if(!$fn($value)) {
            return false;
        }
    }
    return true;
}

【讨论】:

  • 拥有function array_every($a, $c) {return array_filter($a, function ($b) use ($c) {return !$c($b);}) == $a;}可能会更快
  • 您的 $value 缺少 array_every 上的 e,任何人都可以复制和粘贴
  • @cwallenpoole I benchmarked it (ish) 我的版本平均比 array_filter 快 3.6 倍,即使所有调用都返回 true 并且提前退出并不是我的版本平均 1.8 倍的原因速度更快,令我惊讶。
  • @Sylwester 很公平。
【解决方案2】:

不,PHP 标准库中没有 短路 等效项。有许多非短路解决方案,其中array_reduce 可能最适合:

var_dump(array_reduce([2, 5, 8, 1, 4], function ($isBigger, $num) {
    return $isBigger || $num > 10;
}));

可能值得实现您自己的some/any/all 函数,或使用提供此类函数式编程原语集合的库,例如https://github.com/lstrojny/functional-php.

【讨论】:

  • 这将具有与 array_filter 解决方案几乎相同的性能(尽管它可能会更好地使用内存)。
  • 这与 JS Array.some() 的行为不完全相同,因为它在第一个返回 true 的元素上停止,它不会继续其余的 ;)
【解决方案3】:

还有array_filter(),它根据给定回调的返回值返回给定数组的子集。如果子集为空,则相当于 Some() 返回 false,如果不为空,则匹配 Some() 返回 true。

$unfiltered = [1, 11, 2, 22, 3, 33, 4, 44, 5, 55];
$filtered = array_filter ($unfiltered, function ($elem){
    return $elem > 10;
});

print_r ($unfiltered);
print_r ($filtered);
var_dump (empty ($filtered));

但是,这种方法不会短路,并且性能将与数组的大小成反比。不过,这在现实世界中应该无关紧要,因为数组仍然必须变得非常大,或者 array_filter 被调用很多次,然后您才会注意到对性能的影响。

如果性能至关重要,那么您必须自己循环数组,并在找到匹配项后立即跳出循环。

$biggerThanTen = false;
foreach ($unfiltered as $elem)
{
    if ($elem > 10)
    {
        $biggerThanTen = true;
        break;
    }
}

【讨论】:

    【解决方案4】:

    使用 array_filter 并提供回调。把这个包裹在另一个函数中,统计是否有结果

    function array_some(array $data, callable $callback) {
        $result = array_filter($data, $callback);
        return count($result) > 0;
    }
    
    $myarray = [2, 5, 8, 12, 4];
    array_some($myarray, function($value) {
        return $value > 10;
    }); // true
    

    【讨论】:

    • 是的,我想到了这个,但觉得可能效率有点低,因为array_filter返回一个数组,我们立即丢弃
    • 它也不会短路,这可能会非常低效。
    • 我建议你修改你的问题,因为你没有说明你已经尝试过什么。这是最简洁的解决方案,因为没有本地函数可以做到这一点。唯一的另一种方法是迭代并检查每个值...尽早中断并返回 true。
    猜你喜欢
    • 2021-03-19
    • 2010-10-30
    • 2011-02-09
    • 2017-09-11
    • 2015-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多