【问题标题】:What is PHP's equivalent of JavaScript's "array.every()"?什么是 JavaScript“array.every()”的 PHP 等价物?
【发布时间】:2017-12-22 17:23:14
【问题描述】:

我目前正在尝试将一些 JavaScript 移植到 PHP。但是,我似乎找不到与 JavaScript array.every() 函数等效的 PHP。我找到了 PHP 的 each() 函数,但它似乎并不是我所需要的。

【问题讨论】:

  • plain ol' for 循环,当测试条件为假时打破它
  • every 是否检查每个元素是否满足谓词?有时它被称为all
  • 您在下面的评论中说您不太擅长 PHP,但如果您擅长 javascript,请查看 Array#every polyfill 代码并将其转换为 PHP - 也许?

标签: javascript php arrays


【解决方案1】:

使用提前返回的 for 循环。

PHP 没有与 Javascript 的数组#every 执行相同功能的本机函数。

【讨论】:

    【解决方案2】:

    使用foreach():

    function allEven(array $values) 
    {
        foreach ($values as $value) {
            if (1 === $value % 2) {
                return false;
            }
        }
    
        return true;
    }
    
    $data = [
        1,
        42,
        9000,
    ];
    
    $allEven = allEven($data);
    

    参考见:

    注意foreach 比使用array_reduce() 更好,因为一旦发现不满足规范的值,评估就会停止。

    【讨论】:

    • 非常好的答案,因为它 (a) 有一个完整的代码示例并且 (b) 有早期救助,但它可以改进为 accept a callback 而不是硬编码谓词。我不确定您为什么要麻烦链接到array_reduce 文档-该功能不适合此目的(正如您所说!)并且您(正确!)不要在代码中使用它。
    【解决方案3】:

    你可以使用array_reduce函数。

    【讨论】:

    • 我相信这就是我所需要的。 :)
    • 这个方法也被设计成破坏性的,改变你的数组值。
    • array_reduce 很好(我经常使用它),但你应该记住它是你的“当一切都失败时”功能。它每次都会扫描你的整个数组,但是Array#every 应该在回调返回 false 时立即停止运行。
    【解决方案4】:

    php array_every 函数

    
    function array_every($array,$callback)
    {
    
       return  !in_array(false,  array_map($callback,$array));
    }
    
    
    array_every([1,2,3],function($n){
         return $n>0;
    });
    
    

    【讨论】:

    • 我对这个答案投了反对票,因为即使它是一个写得很好的解决方案,它的工作方式也与“每个”不同。当遇到虚假值时,“every”会提前返回(不会调用进一步的回调)。这一个将所有回调,无论它是否在其中一个中遇到虚假值。
    • 可能不考虑性能,我没有考虑,我只是展示如何让它当然你是对的......
    • 注意 foreach 比使用 array_reduce() 更好,因为一旦找到不满足规范的值,评估就会停止。以上说明
    • 这不仅仅是性能,如果传递给every的函数有副作用,它也会触发那些副作用,实际的every-function不会:)
    【解决方案5】:

    此页面上的答案不完整,并更改了 every (JS) / all (Python) 的语义以及其他语言的类似函数。映射和归约是不正确的,因为它们会访问每个元素而不考虑其真值。

    我们需要支持任意谓词的回调,并在定位第一个使谓词函数失败的元素时提供早期救助的功能。 This answer 非常接近,因为它提供了早期救助但未能提供回调谓词。

    我们不妨写some/any

    <?php
    
    function array_every(array $arr, callable $predicate) {
        foreach ($arr as $e) {
            if (!call_user_func($predicate, $e)) {
                 return false;
            }
        }
    
        return true;
    }
    
    function array_any(array $arr, callable $predicate) {
        return !array_every($arr, function ($e) use ($predicate) {
            return !call_user_func($predicate, $e);
        });
    }
    
    // sample predicate
    function is_even($e) {
        return $e % 2 === 0;
    }
    
    var_dump(array_every([0, 1, 2, 3], "is_even")); // => bool(false)
    var_dump(array_every([0, 2], "is_even")); // => bool(true)
    var_dump(array_any([1, 2], "is_even")); // => bool(true)
    var_dump(array_any([1, 3], "is_even")); // => bool(false)
    

    【讨论】:

      【解决方案6】:

      一个简单的解决方案:

      function array_every(array $array, callable $fn) {
        return (bool)array_product(array_map($fn, $array));
      }
      

      在线查看:https://3v4l.org/1D1Ao

      它没有经过优化,只是一个概念证明。对于生产,我会使用 foreach 在第一个未通过测试的项目上返回 false

      【讨论】:

        【解决方案7】:

        这是另一种选择(实际上,很多数组函数都可以非常相似地使用):

        $bool = !empty(array_filter(['my', 'test', 'array'], function ($item) {
            return $item === 'array';
        }));
        

        或者对于 PHP7.4+,使用箭头函数:

        $bool = !empty(array_filter(['my', 'test', 'array'], fn($item) => $item === 'array'));
        

        ...看起来很接近 JS:

        let bool = ['my', 'test', 'array'].every(item => item === 'array'));
        

        然后爆发了:

        function array_every(array $array, callable $callback) {
            return !empty(array_filter($array, $callback));
        }
        
        $myArr = ['my', 'test', 'array'];
        $myTest = fn($item) => $item === 'array'; // PHP7.4+
        $bool = array_every($myArr, $myTest);
        

        同样,可以使用几个数组函数来返回一个空数组或填充数组。尽管正如上面提到的那样,实际的 JS [].every 将在收到 true 返回后立即停止,如果您有一个大数组要迭代,这可以节省大量时间。我遇到了这个问题,正在寻找一种快速的函数式编程风格的代码来迭代三个数组项。

        【讨论】:

          【解决方案8】:

          我准备这个解决方案尽可能接近JavaScript's Array.prototype.every()

          建议的自定义函数:

          说明:

          array_every() 方法测试数组中的所有元素是否通过提供的函数实现的测试。它返回一个布尔值。

          array_every() 方法对数组中存在的每个元素执行一次提供的$callback 函数,直到找到$callback 返回虚假值的那个。如果找到这样的元素,array_every() 方法会立即返回 false。否则,如果$callback 为所有元素返回一个真值,则每个都返回真。

          注意:在空数组上调用此方法将在任何条件下返回 true!

          array_every() 方法不会改变调用它的数组。

          array_every(array $array, string|callable $callback, null|string|object $thisArg = null): bool
          

          参数:

          $数组

          要迭代的数组。

          $回调

          一个用于测试每个元素的回调函数,接受四个参数:

                 $value - 数组中正在处理的元素的当前 value

                 $key(可选)- 数组中正在处理的元素的当前 key

                 $index(可选)- 数组中正在处理的当前元素的索引。

                 $array(可选)- 被遍历的数组。

          $thisArg(可选)

          执行$callback 函数时用作$this 的值。

          返回值:

          true 如果$callback 函数为每个数组元素返回一个真值。否则,false

          array_every() 函数:

          function array_every(array $array, string|callable $callback, null|string|object $thisArg = null): bool
          {
              $index = 0;
          
              foreach ($array as $key => $value) {
          
                  $condition = false;
          
                  if (is_null($thisArg)) {
                      $condition = call_user_func_array($callback, [$value, $key, $index, $array]);
                  } else if (is_object($thisArg) || (is_string($thisArg) && class_exists($thisArg))) {
                      $condition = call_user_func_array([$thisArg, $callback], [$value, $key, $index, $array]);
                  } else if (is_string($thisArg) && !class_exists($thisArg)) {
                      throw new TypeError("Class '$thisArg' not found");
                  }
          
                  if (!$condition)
                      return false;
                  $index++;
              }
              return true;
          }
          

          示例1(简单回调函数):

          $isEven = fn($v) => ($v % 2 === 0);
          
          var_export(array_every([2, 8, 16, 36], $isEven)); // true
          

          示例 2:

          如果将$thisArg 参数提供给array_every() 方法,它将用作$callback$this 值。否则,值null 将用作其$this 值。

          class Helper
          {
              public function isOlderThan18(int $value): bool
              {
                  return $value > 18;
              }
          
              public static function isVowel(string $character): bool
              {
                  return in_array($character, ['a', 'e', 'i', 'o', 'u']);
              }
          
          }
          

          示例 2a) 静态类方法调用:

          如果有问题的类在命名空间下声明,您可以在$thisArg 参数中传递完全限定的类名

          var_export(array_every(["a", "u", "e"], "isVowel", "Helper")); // true
          

          示例 2b) 对象方法调用:

          $thisArg 参数也可以是一个对象。

          var_export(array_every(["Peter" => "35", "Ben" => "16", "Joe" => "43"], "isOlderThan18", (new Helper))); // false
          

          【讨论】:

            【解决方案9】:

            很久以前,我在互联网的黑暗时代写了这个原型,那时你不知道浏览器会做什么。

            是的,这比 jQuery 早了十年。

            它在 JS 中。转换它时,将其用作学习 PHP 的一个很好的练习。

            对你来说有点晚了,但我希望它会有所帮助。

              if ( typeof Array.prototype.every !== 'function' )
              {
              Array.every = Array.prototype.every = function( _callBack, _array )
              {
                  // Assume failure
                  var _matches = false;
            
                  if ( typeof _callBack === 'function' )
                  {
                      // Use ARRAY Object data or passed in data
                      _array = (_array === undefined) ? this : _array;
            
                      // Assume success
                      _matches = true;
            
                      var _len = this.length;
                      for ( var _i = 0; _i < _len; _i++ )
                      {
                          // If this failed, bounce out
                          if ( ! _callBack(this[_i], _i, _array ) )
                              {
                              _matches = false;
                              break;
                          }
                      }
                  }
            
                  return _matches;
              };
            

            }

            【讨论】:

              【解决方案10】:

              我想你可以使用:http://php.net/manual/ru/function.array-map.php

              array array_map(callable $callback, array $array1 [, array $...])

              【讨论】:

              • 我一定会调查的。
              • 如果使用正确,这将返回一个布尔数组,需要再次循环访问,从而降低性能
              • map 改变你的数组。如果你有一个数组 $a = (1, 2, 3, 4) 并且你使用 map:$b = array_map("is_even", $a) 你原来的数组被改变了://$a is now (False, True, False, True)
              • @BrandonBrickyKerr 这与array_map 的工作方式相反。它专门用于当您想要构建一个新数组,而不是改变您的旧数组时。
              • @BrandonBrickyKerr 它不会修改原始数组,而是将其映射到新数组。如果您为同一个变量分配一个新值,那就另当别论了。
              猜你喜欢
              • 2011-04-23
              • 2021-06-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-09-23
              • 2018-10-24
              相关资源
              最近更新 更多