Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Peek ahead when iterating an array in PHP

Is it possible to "peek ahead" while iterating an array in PHP 5.2? For example, I often use foreach to manipulate data from an array:

foreach($array as $object) {
  // do something
}

But I often need to peek at the next element while going through the array. I know I could use a for loop and reference the next item by it's index ($array[$i+1]), but it wouldn't work for associative arrays. Is there any elegant solution for my problem, perhaps involving SPL?

like image 533
pako Avatar asked Mar 16 '10 21:03

pako


4 Answers

You can use the CachingIterator for this purpose.

Here is an example:

$collection = new CachingIterator(
                  new ArrayIterator(
                      array('Cat', 'Dog', 'Elephant', 'Tiger', 'Shark')));

The CachingIterator is always one step behind the inner iterator:

var_dump( $collection->current() ); // null
var_dump( $collection->getInnerIterator()->current() ); // Cat

Thus, when you do foreach over $collection, the current element of the inner ArrayIterator will be the next element already, allowing you to peek into it:

foreach($collection as $animal) {
     echo "Current: $animal";
     if($collection->hasNext()) {
         echo " - Next:" . $collection->getInnerIterator()->current();
     }
     echo PHP_EOL;
 }

Will output:

Current: Cat - Next:Dog
Current: Dog - Next:Elephant
Current: Elephant - Next:Tiger
Current: Tiger - Next:Shark
Current: Shark

For some reason I cannot explain, the CachingIterator will always try to convert the current element to string. If you want to iterate over an object collection and need to access properties an methods, pass CachingIterator::TOSTRING_USE_CURRENT as the second param to the constructor.


On a sidenote, the CachingIterator gets it's name from the ability to cache all the results it has iterated over so far. For this to work, you have to instantiate it with CachingIterator::FULL_CACHE and then you can fetch the cached results with getCache().

like image 161
Gordon Avatar answered Nov 10 '22 10:11

Gordon


Use array_keys.

$keys = array_keys($array);
for ($i = 0; $i < count($keys); $i++) {
    $cur = $array[$keys[$i]];
    $next = $array[$keys[$i+1]];
}
like image 30
Bart van Heukelom Avatar answered Nov 10 '22 08:11

Bart van Heukelom


You can use next and prev to iterate an array. current returns the current items value and key the current key.

So you could do something like this:

while (key($array) !== null) {
    next($array); // set pointer to next element
    if (key($array) === null) {
        // end of array
    } else {
        $nextItem = current($array);
    }
    prev($array); // resetting the pointer to the current element

    // …

    next($array);
}
like image 8
Gumbo Avatar answered Nov 10 '22 09:11

Gumbo


I know that this is an old post, but I can explain that current/next/prev thing better now. Example:

$array = array(1,2,3,2,5);

foreach($array as $k => $v) {
    // in foreach when looping the key() and current() 
    // is already pointing to the next record
    // And now we can print current
    print 'current key: '.$k.' and value: '.$v;
    // if we have next we can print its information too (key+value)
    if(current($array)) {
         print ' - next key: '.key($array).' and value: '.current($array);
         // at the end we must move pointer to next
         next($array);
    }
    print '<br>';
}

// prints:
// current key: 0 and value: 1 - next key: 1 and value: 2
// current key: 1 and value: 2 - next key: 2 and value: 3
// current key: 2 and value: 3 - next key: 3 and value: 2
// current key: 3 and value: 2 - next key: 4 and value: 5
// current key: 4 and value: 5
like image 4
Juhani Avatar answered Nov 10 '22 10:11

Juhani