在foreach循环中获取下一个元素

67

我有一个foreach循环,希望可以知道是否还有下一个元素,这样就能将当前元素与下一个元素进行比较。我该如何做?我已经了解了current和next函数,但是不知道如何使用它们。


从第2个元素开始与第1个元素比较,是否可以接受? - Marc B
11个回答

45

一种独特的方法是先反转数组,然后再进行循环。这也适用于非数字索引数组:

$items = array(
    'one'   => 'two',
    'two'   => 'two',
    'three' => 'three'
);
$backwards = array_reverse($items);
$last_item = NULL;

foreach ($backwards as $current_item) {
    if ($last_item === $current_item) {
        // they match
    }
    $last_item = $current_item;
}

如果您仍然有兴趣使用currentnext函数,您可以这样做:

$items = array('two', 'two', 'three');
$length = count($items);
for($i = 0; $i < $length - 1; ++$i) {
    if (current($items) === next($items)) {
        // they match
    }
}

#2 可能是最佳解决方案。请注意,$i < $length - 1;将在比较数组的最后两个项后停止循环。我在循环中放置了这个内容以明确示例。您应该只计算$length = count($items) - 1;


31

你可以尝试使用 while 循环而不是 foreach:

while ($current = current($array) )
{
    $next = next($array);
    if (false !== $next && $next == $current)
    {
        //do something with $current
    }
}

1
请记住,在执行此操作之前,您可能需要先使用reset($array)将指针设置为第一个元素。 - Jonathan

14
如果索引是连续的:
foreach ($arr as $key => $val) {
   if (isset($arr[$key+1])) {
      echo $arr[$key+1]; // next element
   } else {
     // end of array reached
   }
}

4
这不是真的,试试这个:array(1 => 'a', 0 => 'b', 100 => 'c'); - Eduardo Romero
16
@EduardoRomero 没错,这就是我为什么提到:“如果索引是连续的”的原因。 - Mārtiņš Briedis

12
根据php.net/foreach的说明:
如果没有引用数组,foreach将操作指定数组的副本而不是数组本身。foreach对数组指针有一些副作用,请勿在foreach期间或之后依赖该数组指针而不重置它。
换句话说 - 做你所要求的事情不是一个很好的主意。也许与某人谈论为什么要尝试这样做,并查看是否有更好的解决方案是一个好主意?如果您没有其他资源可用,可以在irc.freenode.net的##PHP上问我们。

9
你可以获取键/值和索引。
<?php
$a = array(
    'key1'=>'value1', 
    'key2'=>'value2', 
    'key3'=>'value3', 
    'key4'=>'value4', 
    'key5'=>'value5'
);

$keys = array_keys($a);
foreach(array_keys($keys) as $index ){       
    $current_key = current($keys); // or $current_key = $keys[$index];
    $current_value = $a[$current_key]; // or $current_value = $a[$keys[$index]];

    $next_key = next($keys); 
    $next_value = $a[$next_key] ?? null; // for php version >= 7.0

    echo  "{$index}: current = ({$current_key} => {$current_value}); next = ({$next_key} => {$next_value})\n";
}

结果:

0: current = (key1 => value1); next = (key2 => value2) 
1: current = (key2 => value2); next = (key3 => value3) 
2: current = (key3 => value3); next = (key4 => value4) 
3: current = (key4 => value4); next = (key5 => value5) 
4: current = (key5 => value5); next = ( => )

2
不错!可以使用字符串作为键。 - Lucas Bustamante

4

如果它是按数字索引的:

foreach ($foo as $key=>$var){

    if($var==$foo[$key+1]){
        echo 'current and next var are the same';
    }
}

当然,不能使用这个答案,因为在最后一次迭代中,将无法访问$foo中的$key+1键。 - mickmackusa

4

一般的解决方案可能是使用缓存迭代器。一个正确实现的缓存迭代器可以与任何迭代器一起使用,并且可以节省内存。PHP SPL提供了CachingIterator,但它非常奇怪,并且功能非常有限。不过,你可以编写自己的前瞻迭代器,像这样:

<?php

class NeighborIterator implements Iterator
{

    protected $oInnerIterator;

    protected $hasPrevious = false;
    protected $previous = null;
    protected $previousKey = null;

    protected $hasCurrent = false;
    protected $current = null;
    protected $currentKey = null;

    protected $hasNext = false;
    protected $next = null;
    protected $nextKey = null;

    public function __construct(Iterator $oInnerIterator)
    {
        $this->oInnerIterator = $oInnerIterator;
    }

    public function current()
    {
        return $this->current;
    }

    public function key()
    {
        return $this->currentKey;
    }

    public function next()
    {
        if ($this->hasCurrent) {
            $this->hasPrevious = true;
            $this->previous = $this->current;
            $this->previousKey = $this->currentKey;
            $this->hasCurrent = $this->hasNext;
            $this->current = $this->next;
            $this->currentKey = $this->nextKey;
            if ($this->hasNext) {
                $this->oInnerIterator->next();
                $this->hasNext = $this->oInnerIterator->valid();
                if ($this->hasNext) {
                    $this->next = $this->oInnerIterator->current();
                    $this->nextKey = $this->oInnerIterator->key();
                } else {
                    $this->next = null;
                    $this->nextKey = null;
                }
            }
        }
    }

    public function rewind()
    {
        $this->hasPrevious = false;
        $this->previous = null;
        $this->previousKey = null;
        $this->oInnerIterator->rewind();
        $this->hasCurrent = $this->oInnerIterator->valid();
        if ($this->hasCurrent) {
            $this->current = $this->oInnerIterator->current();
            $this->currentKey = $this->oInnerIterator->key();
            $this->oInnerIterator->next();
            $this->hasNext = $this->oInnerIterator->valid();
            if ($this->hasNext) {
                $this->next = $this->oInnerIterator->current();
                $this->nextKey = $this->oInnerIterator->key();
            } else {
                $this->next = null;
                $this->nextKey = null;
            }
        } else {
            $this->current = null;
            $this->currentKey = null;
            $this->hasNext = false;
            $this->next = null;
            $this->nextKey = null;
        }
    }

    public function valid()
    {
        return $this->hasCurrent;
    }

    public function hasNext()
    {
        return $this->hasNext;
    }

    public function getNext()
    {
        return $this->next;
    }

    public function getNextKey()
    {
        return $this->nextKey;
    }

    public function hasPrevious()
    {
        return $this->hasPrevious;
    }

    public function getPrevious()
    {
        return $this->previous;
    }

    public function getPreviousKey()
    {
        return $this->previousKey;
    }

}


header("Content-type: text/plain; charset=utf-8");
$arr = [
    "a" => "alma",
    "b" => "banan",
    "c" => "cseresznye",
    "d" => "dio",
    "e" => "eper",
];
$oNeighborIterator = new NeighborIterator(new ArrayIterator($arr));
foreach ($oNeighborIterator as $key => $value) {

    // you can get previous and next values:

    if (!$oNeighborIterator->hasPrevious()) {
        echo "{FIRST}\n";
    }
    echo $oNeighborIterator->getPreviousKey() . " => " . $oNeighborIterator->getPrevious() . " ----->        ";
    echo "[ " . $key . " => " . $value . " ]        -----> ";
    echo $oNeighborIterator->getNextKey() . " => " . $oNeighborIterator->getNext() . "\n";
    if (!$oNeighborIterator->hasNext()) {
        echo "{LAST}\n";
    }
}

2

在使用foreach之前,您可以获取数组的键,然后使用计数器来检查下一个元素,例如:

//$arr is the array you wish to cycle through
$keys = array_keys($arr);
$num_keys = count($keys);
$i = 1;
foreach ($arr as $a)
{
    if ($i < $num_keys && $arr[$keys[$i]] == $a)
    {
        // we have a match
    }
    $i++;
}

这适用于简单数组,例如array(1,2,3),以及关联数组,例如array('first'=>1, 'second'=>2, 'thrid'=>3)


2

在PHP中,foreach循环将遍历原始数组的一个副本,导致next()prev()函数无效。如果你有一个关联数组并需要获取下一个元素,则可以遍历数组键:

foreach (array_keys($items) as $index => $key) {
    // first, get current item
    $item = $items[$key];
    // now get next item in array
    $next = $items[array_keys($items)[$index + 1]];
}

由于生成的键数组本身具有连续的索引,因此您可以使用它来访问原始数组。请注意,由于最后一次迭代后没有下一个项目,因此 $next 将为 null。访问不存在的数组键将抛出 php 注意。为了避免这种情况,请执行以下操作之一:1. 在分配值给 $next 之前检查最后一次迭代;2. 使用 array_key_exists() 检查具有 index + 1 的键是否存在。使用方法 2,完整的 foreach 可以如下所示:
foreach (array_keys($items) as $index => $key) {
    // first, get current item
    $item = $items[$key];
    // now get next item in array
    $next = null;
    if (array_key_exists($index + 1, array_keys($items))) {
        $next = $items[array_keys($items)[$index + 1]];
    }
}

2
在每次迭代中使用array_keys?这一定是最慢的解决方案。 - Semra

0

或者如果数组是关联数组,那么你可以使用current(),类似于Andrei Krasutski的解决方案和key()

$values = [];
array_push($values, ["XYZ"=>100]);
array_push($values, ["ABC"=>10]);
array_push($values, ["XYZ"=>130]);
array_push($values, ["DEF"=>4]);
array_push($values, ["XYZ"=>5]);

$count = count($values);

foreach ($values as $index => $currentValue) {

    if ($index < $count - 1) {

        $nextValue = $values[$index + 1];
        echo key($currentValue) . "=" . current($currentValue) . " followed by  " . key($nextValue) . "/" . current($nextValue) . "<br>\n";

    } else {

        echo key($currentValue) . "=" . current($currentValue);

    }
}

请查看https://onlinephp.io/c/dc58d以获取一个运行示例。

或者,如果数组使用命名对:

$values = [];
array_push($values, ["type"=>"XYZ", "value"=>100]);
array_push($values, ["type"=>"ABC", "value"=>10]);
array_push($values, ["type"=>"XYZ", "value"=>130]);
array_push($values, ["type"=>"DEF", "value"=>"Lorem"]);
array_push($values, ["type"=>"XYZ", "value"=>5]);

$count = count($values);

foreach ($values as $index => $currentValue) {
    if ($index < $count - 1) {
        $nextValue = $values[$index + 1];
        echo $currentValue['type'] . "=" . $currentValue['value'] 
        . "  followed by  " . $nextValue['type'] . "/" . $nextValue['value'] . "<br>\n";
    } else {
        echo $currentValue['type'] . "=" . $currentValue['value'];
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接