Reputation: 19812
I have a foreach loop and I want to see if there is a next element in the loop so I can compare the current element with the next. How can I do this? I've read about the current and next functions but I can't figure out how to use them.
Upvotes: 69
Views: 165885
Reputation: 359
You can simply save array keys in a variable:
$arrayKeys = array_keys($array);
and find by that in your foreach loop:
foreach ($array as $key => $value ) {
$nextKey = $arrayKeys[array_search($key, $arrayKeys) + 1];
}
Upvotes: -1
Reputation: 1316
or if the array is associative then you could use current()
similar to Andrei Krasutski's solution and 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);
}
}
See https://onlinephp.io/c/dc58d for a running example.
or if the array is using named pairs:
$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'];
}
}
Upvotes: 0
Reputation: 171
$next_data = $data;
$prev_key = null;
$prev_value = null;
foreach($data as $key => $value)
{
array_shift($next_data);
$next_key = key($next_data);
$next_value = $next_data[$next_key] ?? null;
// Do something here...
$prev_key = $key;
$prev_value = $value;
}
Upvotes: 0
Reputation: 17762
If the indexes are continuous:
foreach ($arr as $key => $val) {
if (isset($arr[$key+1])) {
echo $arr[$key+1]; // next element
} else {
// end of array reached
}
}
Upvotes: 16
Reputation: 5257
You could get the keys/values and 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";
}
result:
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 = ( => )
Upvotes: 8
Reputation: 4320
The general solution could be a caching iterator. A properly implemented caching iterator works with any Iterator, and saves memory. PHP SPL has a CachingIterator, but it is very odd, and has very limited functionality. However, you can write your own lookahead iterator like this:
<?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";
}
}
Upvotes: 4
Reputation: 3807
A foreach loop in php will iterate over a copy of the original array, making next()
and prev()
functions useless. If you have an associative array and need to fetch the next item, you could iterate over the array keys instead:
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]];
}
Since the resulting array of keys has a continuous index itself, you can use that instead to access the original array.
Be aware that $next
will be null
for the last iteration, since there is no next item after the last. Accessing non existent array keys will throw a php notice. To avoid that, either:
$next
index + 1
exists with array_key_exists()
Using method 2 the complete foreach could look like this:
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]];
}
}
Upvotes: 1
Reputation: 1358
You could probably use while loop instead of foreach:
while ($current = current($array) )
{
$next = next($array);
if (false !== $next && $next == $current)
{
//do something with $current
}
}
Upvotes: 31
Reputation:
if its numerically indexed:
foreach ($foo as $key=>$var){
if($var==$foo[$key+1]){
echo 'current and next var are the same';
}
}
Upvotes: 3
Reputation: 396
You could get the keys of the array before the foreach, then use a counter to check the next element, something like:
//$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++;
}
This will work for both simple arrays, such as array(1,2,3)
, and keyed arrays such as array('first'=>1, 'second'=>2, 'thrid'=>3)
.
Upvotes: 3
Reputation: 12966
As php.net/foreach points out:
Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it.
In other words - it's not a very good idea to do what you're asking to do. Perhaps it would be a good idea to talk with someone about why you're trying to do this, see if there's a better solution? Feel free to ask us in ##PHP on irc.freenode.net if you don't have any other resources available.
Upvotes: 13
Reputation: 18964
A unique approach would be to reverse the array and then loop. This will work for non-numerically indexed arrays as well:
$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;
}
If you are still interested in using the current
and next
functions, you could do this:
$items = array('two', 'two', 'three');
$length = count($items);
for($i = 0; $i < $length - 1; ++$i) {
if (current($items) === next($items)) {
// they match
}
}
#2 is probably the best solution. Note, $i < $length - 1;
will stop the loop after comparing the last two items in the array. I put this in the loop to be explicit with the example. You should probably just calculate $length = count($items) - 1;
Upvotes: 47