【问题标题】:Iterate in reverse through an array with PHP - SPL solution?使用 PHP - SPL 解决方案反向遍历数组?
【发布时间】:2011-07-15 23:47:37
【问题描述】:

PHP 中是否有 SPL 反向数组迭代器? 如果没有,实现它的最佳方法是什么?

我可以这样做

$array = array_reverse($array);
foreach($array as $currentElement) {}

for($i = count($array) - 1; $i >= 0; $i--)
{

}

但是还有更优雅的方式吗?

【问题讨论】:

  • 你的第二种方法不一定对。仅适用于数字连续键
  • 糟糕,是的,这是真的。就我而言,我有一个数字数组,但您的评论使我认为我的问题更加相关。
  • 数值数组不一定按顺序排列,也不一定从0开始

标签: php reverse loops spl


【解决方案1】:
$item=end($array);
do {
...
} while ($item=prev($array));

【讨论】:

  • end 将内部数组迭代器设置为最后一个元素并返回它。 prev 返回当前元素并将迭代器设置为前一个元素。
  • 实际上,第二个版本会跳过数组的最后一个元素。
  • 投反对票。第二个版本跳过最后一个元素。
  • 如果数组的值之一是 false 或 NULL 或 0 怎么办?
【解决方案2】:
$array = array_reverse($array);
foreach($array as $key => $currentElement) {}

这是更好的使用方式。如果它们不是顺序的或整数的,它也会处理键。

【讨论】:

  • 如果您不需要保留反向数组,可以将其缩短为 foreach(array_reverse($array, true) ...。请记住 array_reverse 的第二个参数,它保留了密钥。
【解决方案3】:

根据您要执行的操作,您可能需要查看 spl 数据结构类,例如 SplStack。 SplStack 实现了 Iterator、ArrayAccess 和 Countable,因此它主要可以像数组一样使用,但默认情况下,它的迭代器按 FILO 顺序进行。例如:

$stack = new SplStack();
$stack[] = 'one';
$stack[] = 'two';
$stack[] = 'three';

foreach ($stack as $item)
{
    print "$item\n";
}

这将打印出来

three
two
one

【讨论】:

    【解决方案4】:

    没有ReverseArrayIterator 可以做到这一点。你可以这样做

    $reverted = new ArrayIterator(array_reverse($data));
    

    或者把它变成你自己的自定义迭代器,例如

    class ReverseArrayIterator extends ArrayIterator 
    {
        public function __construct(array $array)
        {
            parent::__construct(array_reverse($array));
        }
    }
    

    不使用array_reverse但通过标准数组函数迭代数组的稍长的实现将是

    class ReverseArrayIterator implements Iterator
    {
        private $array;
    
        public function __construct(array $array)
        {
            $this->array = $array;
        }
    
        public function current()
        {
            return current($this->array);
        }
    
        public function next()
        {
            return prev($this->array);
        }
    
        public function key()
        {
            return key($this->array);
        }
    
        public function valid()
        {
            return key($this->array) !== null;
        }
    
        public function rewind()
        {
            end($this->array);
        }
    }
    

    【讨论】:

    • 我建议做 array_reverse($array, true) 以保留数字键的键关联。
    • 请记住,array_reverse 复制数组元素,因此性能不是很明智
    • array_reverse 很昂贵,我不建议您每次需要迭代时都这样做。最好从一开始就以相反的顺序存储东西或使用@linepogl的解决方案。
    • 不优雅地反转整个数组,这个回复实际上并没有改变 OP 解决方案的任何内容,只是在原始解决方案中添加了语法糖(甚至更多开销)。
    • @FrancescoMM 没有人要求一个优雅的解决方案。虽然它并没有比程序方法增加太多,但 OP 特别要求使用 SPL 迭代器。
    【解决方案5】:

    注意,如果要保留数组的键,必须将true作为第二个参数传递给array_reverse

    $array = array_reverse($array, true);
    foreach ($array as $currentElement) {
        // do something here
    }
    

    【讨论】:

      【解决方案6】:

      这可能是一种更高效的方式,因为它不构造新数组。它还可以很好地处理空数组。

      $item = end($items);
      while($item)
      {
          ...do stuff...
          $item = prev($items);
      }
      

      【讨论】:

      • 如果其中一项的值为 false 或 NULL 或 0 怎么办?
      【解决方案7】:

      这里是一个不复制也不修改数组的解决方案:

      for (end($array); key($array)!==null; prev($array)){
        $currentElement = current($array);
        // ...
      }
      

      如果您还想引用当前键:

      for (end($array); ($currentKey=key($array))!==null; prev($array)){
        $currentElement = current($array);
        // ...
      }
      

      这总是有效的,因为 php 数组键永远不能为空,并且比这里给出的任何其他答案都快。

      【讨论】:

      • 最佳答案在这里。谢谢!
      • 这是一个遍历数组的正确解决方案,以相反的顺序获取任何键(数字或非数字)和值(包括空值)。
      • 虽然 OP 要求提供迭代器。
      【解决方案8】:
      $array=array(
          0 => 0,
          '1' => 1,
          2 => null,
          3 => false
      );
      
      $value=end( $array );                      // ← value for first iteration
      while(($key=key( $array )) !== null) {
        echo "key=$key, value=$value\n";
      
        $value=prev( $array );                   // ← value for next iteration
      }
      

      【讨论】:

      • 没有解释的代码转储很少有帮助。请考虑在您的答案中添加一些上下文。
      【解决方案9】:

      $array1= 数组(10,20,30,40,50);

              for($i = count($array1) - 1; $i >= 0; $i--)
              {
                  $array2[]  = $array1[$i];
      
              }
      
              echo "<pre>";
                  print_r($array2);
              echo "</pre>";
      

      【讨论】:

        【解决方案10】:

        基于linepogl's answer,我想出了这个函数:

        /**
         * Iterate an array or other foreach-able without making a copy of it.
         *
         * @param array|\Traversable $iterable
         * @return Generator
         */
        function iter_reverse($iterable) {
            for (end($iterable); ($key=key($iterable))!==null; prev($iterable)){
                yield $key => current($iterable);
            }
        }
        

        用法:

        foreach(iter_reverse($my_array) as $key => $value) {
            // ... do things ...
        }
        

        这适用于数组和其他可迭代对象,而无需先复制它。

        【讨论】:

          【解决方案11】:

          基于linepogl 的 回答...您可以通过避免current() 调用来提高效率

          for ($value = end($array); ($key = key($array)) !== null; $value = prev($array)) {
               // ... do something with $key => $value
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-08-16
            • 1970-01-01
            相关资源
            最近更新 更多