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




(9)

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


Answers

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, etwa:

//$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) .


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

Wie php.net/foreach darauf hinweist:

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 herauszufinden, 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.


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öchten, 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 über einen kontinuierlichen Index verfügt, können Sie stattdessen auf das ursprüngliche Array zugreifen.

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

  1. Suchen Sie nach der letzten Iteration, bevor Sie $next Werte zuweisen
  2. Prüfen Sie mit array_key_exists() ob der Schlüssel mit index + 1 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]];
    }
}

wenn es numerisch indiziert ist:

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

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

Ein einzigartiger Ansatz wäre die Umkehrung des Arrays und die anschließende Schleife. 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 sich immer noch für die Verwendung der current und der next Funktionen interessieren, 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. Beachten Sie, $i < $length - 1; stoppt die Schleife nach dem Vergleich der letzten beiden Elemente im Array. Ich habe dies in die Schleife gestellt, um mit dem Beispiel explizit zu sein. Sie sollten wahrscheinlich nur $length = count($items) - 1; berechnen $length = count($items) - 1;


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

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 , der aber sehr seltsam ist und nur über eine eingeschränkte Funktionalität verfügt. 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";
    }
}

Konnte so etwas tun:

public static class ForEachExtensions
{
    public static void ForEachWithIndex<T>(this IEnumerable<T> enumerable, Action<T, int> handler)
    {
        int idx = 0;
        foreach (T item in enumerable)
            handler(item, idx++);
    }
}

public class Example
{
    public static void Main()
    {
        string[] values = new[] { "foo", "bar", "baz" };

        values.ForEachWithIndex((item, idx) => Console.WriteLine("{0}: {1}", idx, item));
    }
}




php foreach