J'ai une boucle foreach et je veux voir s'il y a un élément suivant dans la boucle afin de pouvoir comparer l'élément en cours avec le suivant. Comment puis-je faire ceci? J'ai lu des informations sur les fonctions actuelles et suivantes, mais je ne sais pas comment les utiliser.
Merci d'avance
Une approche unique consisterait à inverser le tableau et puis boucle. Cela fonctionnera également pour les tableaux non indexés numériquement:
$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 vous souhaitez toujours utiliser les fonctions current
et next
, vous pouvez procéder comme suit:
$items = array('two', 'two', 'three');
$length = count($items);
for($i = 0; $i < $length - 1; ++$i) {
if (current($items) === next($items)) {
// they match
}
}
# 2 est probablement la meilleure solution. Notez que $i < $length - 1;
arrêtera la boucle après avoir comparé les deux derniers éléments du tableau. Je mets cela dans la boucle pour être explicite avec l'exemple. Vous devriez probablement simplement calculer $length = count($items) - 1;
Vous pourriez probablement utiliser la boucle while au lieu de foreach:
while ($current = current($array) )
{
$next = next($array);
if (false !== $next && $next == $current)
{
//do something with $current
}
}
Comme php.net/foreach fait remarquer:
À moins que le tableau ne soit référencé, foreach agit sur une copie du tableau spécifié et non sur le tableau lui-même. foreach a des effets secondaires sur le pointeur du tableau. Ne comptez pas sur le pointeur de tableau pendant ou après le foreach sans le réinitialiser.
En d'autres termes, ce n'est pas une très bonne idée de faire ce que vous demandez de faire. Peut-être que ce serait une bonne idée de parler à quelqu'un de la raison pour laquelle vous essayez de faire cela, voir s'il existe une meilleure solution? N'hésitez pas à nous demander en ## PHP sur irc.freenode.net si vous n'avez aucune autre ressource disponible.
Si les index sont continus:
foreach ($arr as $key => $val) {
if (isset($arr[$key+1])) {
echo $arr[$key+1]; // next element
} else {
// end of array reached
}
}
si son index numérique:
foreach ($foo as $key=>$var){
if($var==$foo[$key+1]){
echo 'current and next var are the same';
}
}
La solution générale pourrait être un itérateur de cache. Un itérateur de mise en cache correctement implémenté fonctionne avec n'importe quel Iterator et économise de la mémoire. PHP SPL a un CachingIterator , mais il est très étrange et ses fonctionnalités sont très limitées. Cependant, vous pouvez écrire votre propre itérateur lookahead comme ceci:
<?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";
}
}
Vous pouvez obtenir les clés du tableau avant foreach, puis utiliser un compteur pour vérifier l'élément suivant, quelque chose comme:
//$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++;
}
Cela fonctionnera pour les tableaux simples, tels que array(1,2,3)
, et les tableaux à clé tels que array('first'=>1, 'second'=>2, 'thrid'=>3)
.
Une boucle foreach en php va parcourir une copie du tableau d'origine, rendant les fonctions next()
et prev()
inutiles. Si vous avez un tableau associatif et devez récupérer l'élément suivant, vous pouvez plutôt effectuer une itération sur les clés du tableau:
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]];
}
Étant donné que le tableau de clés résultant a lui-même un index continu, vous pouvez l'utiliser à la place pour accéder au tableau d'origine.
Soyez conscient que $next
sera null
pour la dernière itération, car il n'y a aucun élément suivant après la dernière. L'accès à des clés de tableau non existantes jettera un avis php. Pour éviter cela, soit:
$next
index + 1
existe avec array_key_exists()
En utilisant la méthode 2, le foreach complet pourrait ressembler à ceci:
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]];
}
}
Vous pouvez obtenir les clés/valeurs et index
<?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";
}
résultat:
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 = ( => )