2011-02-23 15 views
35

Tengo un bucle foreach y quiero ver si hay un elemento siguiente en el bucle para poder comparar el elemento actual con el siguiente. ¿Cómo puedo hacer esto? He leído sobre las funciones actuales y siguientes, pero no puedo entender cómo usarlas.Obtener el siguiente elemento en el bucle foreach

Gracias de antemano

+0

¿Sería aceptable comenzar en el elemento n. ° 2 y compararlo con el elemento n. ° 1? –

+0

No debe comenzar desde 1 – chchrist

Respuesta

24

Un enfoque único sería la de invertir la matriz y continuación bucle. Esto funcionará para las matrices no indexado numéricamente así:

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

Si usted todavía está interesado en el uso de los current y next funciones, usted puede hacer esto:

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

# 2 es probablemente el mejor solución. Tenga en cuenta que $i < $length - 1; detendrá el ciclo después de comparar los dos últimos elementos de la matriz. Puse esto en el circuito para ser explícito con el ejemplo. Probablemente deberías hacer el cálculo $length = count($items) - 1;

6

Si índices ar Continious:

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

Esto no es cierto, intente: matriz (1 => 'a', 0 => 'b', 100 => 'c'); –

+7

@EduardoRomero sí, es por eso que mencioné: 'Si los índices son continuos' –

4

si es indexado numéricamente:

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

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

usted podría conseguir las claves de la matriz antes de la foreach, a continuación, utilizar un contador para comprobar el siguiente elemento, algo así como:

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

Esto funcionará para ambas matrices simples, como array(1,2,3) y matrices con clave como array('first'=>1, 'second'=>2, 'thrid'=>3).

8

Como php.net/foreach señala:

A menos que se hace referencia a la matriz, foreach funciona con una copia de la matriz especificada y no a la propia matriz. foreach tiene algunos efectos secundarios en el puntero del array. No confíe en el puntero de matriz durante o después del foreach sin restablecerlo.

En otras palabras, no es una buena idea hacer lo que está pidiendo que haga. Tal vez sería una buena idea hablar con alguien sobre por qué intentas hacer esto, ver si hay una mejor solución. No dude en consultarnos en ## PHP en irc.freenode.net si no tiene otros recursos disponibles.

9

Probablemente se podría utilizar el bucle while en lugar de foreach:

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

Encontré esto útil ... ¡gracias! –

+0

Solo recuerde, es posible que deba 'reset ($ array)' antes de esto, ya que el puntero no se puede establecer en el primer elemento. – Jonathan

0

un bucle foreach en php se iterar sobre una copia de la matriz original, por lo que next() y prev() funciones inútiles. Si usted tiene un arreglo asociativo y la necesidad de buscar el siguiente punto, se podría iterar sobre las claves de matriz en su lugar:

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

Dado que la matriz resultante de llaves tiene un índice continuo en sí, puede utilizar que en lugar de acceder a la matriz original

Tenga en cuenta que$next será null para la última iteración, ya que no hay orden del día, después de la última. El acceso a claves de matriz no existentes arrojará un aviso php. Para evitar esto, ya sea:

  1. Comprobar si la última iteración antes de la asignación de valores a $next
  2. Comprobar si la llave con index + 1 existe con array_key_exists()

Utilizando el método 2, el foreach completa podría tener este aspecto :

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

¿Usando array_keys en cada iteración? Esta debe ser la solución más lenta. – Semra

2

La solución general podría ser un iterador de almacenamiento en caché. Un iterador de caché implementado correctamente funciona con cualquier iterador y guarda la memoria. PHP SPL tiene un CachingIterator, pero es muy extraño y tiene una funcionalidad muy limitada. Sin embargo, puede escribir su propio iterador de anticipación así:

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