wake-up-neo.com

Holen Sie sich das nächste Element in der foreach-Schleife

Ich habe eine foreach-Schleife und möchte sehen, ob es ein nächstes Element in der Schleife gibt, sodass ich das aktuelle Element mit dem nächsten vergleichen kann. Wie kann ich das machen? Ich habe über die aktuellen und die nächsten Funktionen gelesen, kann aber nicht herausfinden, wie sie verwendet werden.

Danke im Voraus

41
chchrist

Ein einzigartiger Ansatz wäre, das Array und dann Loop umzukehren. Dies funktioniert auch für nicht numerisch indizierte Arrays:

$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;
}

Wenn Sie weiterhin an der Verwendung der Funktionen current und next interessiert sind, können Sie Folgendes tun:

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

# 2 ist wahrscheinlich die beste Lösung. Hinweis: $i < $length - 1; stoppt die Schleife, nachdem die letzten beiden Elemente im Array verglichen wurden. Ich habe dies in die Schleife gestellt, um mit dem Beispiel explizit zu sein. Sie sollten wahrscheinlich nur $length = count($items) - 1; berechnen

29
Stephen

Sie könnten wahrscheinlich while-Schleife anstelle von foreach verwenden:

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

Wie php.net/foreach weist darauf hin:

Wenn auf das Array nicht verwiesen wird, verarbeitet foreach eine Kopie des angegebenen Arrays und nicht das Array selbst. foreach hat einige Nebeneffekte auf den Arrayzeiger. Verlassen Sie sich während oder nach dem foreach nicht auf den Array-Zeiger, ohne ihn zurückzusetzen.

Mit anderen Worten - es ist keine sehr gute Idee, das zu tun, was Sie wollen. Vielleicht wäre es eine gute Idee, mit jemandem darüber zu sprechen, warum Sie dies versuchen, um zu sehen, ob es eine bessere Lösung gibt? Fragen Sie uns in ## PHP auf irc.freenode.net, wenn Sie keine anderen Ressourcen zur Verfügung haben.

10
TML

Wenn die Indizes kontinuierlich sind:

foreach ($arr as $key => $val) {
   if (isset($arr[$key+1])) {
      echo $arr[$key+1]; // next element
   } else {
     // end of array reached
   }
}
7

wenn es numerisch indiziert ist:

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

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

Die allgemeine Lösung könnte ein Cache-Iterator sein. Ein ordnungsgemäß implementierter Cache-Iterator kann mit jedem Iterator verwendet werden und spart Speicher. PHP SPL hat einen CachingIterator , ist aber sehr seltsam und hat eine sehr eingeschränkte Funktionalität. Sie können jedoch Ihren eigenen Lookahead-Iterator folgendermaßen schreiben:

<?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";
    }
}
3
Dávid Horváth

Sie könnten die Schlüssel des Arrays vor dem foreach abrufen und dann einen Zähler verwenden, um das nächste Element zu überprüfen.

//$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++;
}

Dies funktioniert sowohl für einfache Arrays wie array(1,2,3) als auch für Keyed Arrays wie array('first'=>1, 'second'=>2, 'thrid'=>3).

2
eclipse31

Eine foreach-Schleife in php durchläuft eine Kopie des ursprünglichen Arrays, wodurch die Funktionen next() und prev() unbrauchbar werden. Wenn Sie über ein assoziatives Array verfügen und das nächste Element abrufen müssen, können Sie stattdessen die Array-Schlüssel durchlaufen:

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]];
}

Da das resultierende Array von Schlüsseln selbst einen fortlaufenden Index hat, können Sie stattdessen auf das ursprüngliche Array zugreifen.

Beachten Sie dass $next für die letzte Iteration null ist, da nach dem letzten kein nächster Artikel vorhanden ist. Wenn Sie auf nicht vorhandene Array-Schlüssel zugreifen, wird eine PHP-Benachrichtigung ausgegeben. Um das zu vermeiden, entweder:

  1. Suchen Sie nach der letzten Iteration, bevor Sie $next Werte zuweisen.
  2. Prüfen Sie, ob der Schlüssel mit index + 1 mit array_key_exists() existiert.

Bei Verwendung von Methode 2 könnte das komplette Foreach folgendermaßen aussehen:

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]];
    }
}
0
Liquinaut

Sie könnten die Schlüssel/Werte und den Index erhalten

<?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";
}

ergebnis:

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 = ( => )
0