Взгляд вперед при итерации массива в PHP - PullRequest
29 голосов
/ 17 марта 2010

Можно ли «заглянуть вперед» при переборе массива в PHP 5.2? Например, я часто использую foreach для манипулирования данными из массива:

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

Но при просмотре массива мне часто приходится заглядывать в следующий элемент. Я знаю, что могу использовать цикл for и ссылаться на следующий элемент по его индексу ($array[$i+1]), но он не будет работать для ассоциативных массивов. Есть ли какое-нибудь элегантное решение для моей проблемы, возможно, с использованием SPL?

Ответы [ 5 ]

52 голосов
/ 17 марта 2010

Вы можете использовать CachingIterator для этой цели.

Вот пример:

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

CachingIterator всегда на один шаг позади внутреннего итератора:

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

Таким образом, когда вы делаете foreach над $collection, текущий элемент внутреннего ArrayIterator уже будет следующим элементом, позволяя вам заглянуть в него:

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

Будет выводить:

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

По какой-то причине я не могу объяснить, CachingIterator всегда будет пытаться преобразовать текущий элемент в строку. Если вы хотите перебрать коллекцию объектов и получить доступ к свойствам методов, передайте CachingIterator::TOSTRING_USE_CURRENT в качестве второго параметра конструктору.


В sidenote CachingIterator получил свое имя благодаря способности кэшировать все результаты, которые он повторял до сих пор. Чтобы это работало, вы должны создать его экземпляр с помощью CachingIterator::FULL_CACHE, а затем вы можете получить кэшированные результаты с помощью getCache().

18 голосов
/ 17 марта 2010

Использование array_keys.

$keys = array_keys($array);
for ($i = 0; $i < count($keys); $i++) {
    $cur = $array[$keys[$i]];
    $next = $array[$keys[$i+1]];
}
7 голосов
/ 17 марта 2010

Вы можете использовать next и prev для итерации массива. current возвращает текущее значение элемента и key текущий ключ.

Так что вы можете сделать что-то вроде этого:

while (key($array) !== null) {
    next($array);
    if (key($array) === null) {
        // end of array
    } else {
        $nextItem = value($array);
    }
    prev($array);

    // …

    next($array);
}
3 голосов
/ 17 сентября 2012

Я знаю, что это старый пост, но я могу объяснить, что текущая / следующая / предыдущая вещь лучше сейчас. Пример:

$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
0 голосов
/ 12 марта 2013

Я знаю, что мог бы использовать цикл for и ссылаться на следующий элемент по его индексу ($ array [$ i + 1]), но он не будет работать для ассоциативных массивов.

Рассмотрите возможность преобразования вашего ассоциативного массива в последовательно индексированный с помощью array_values ​​() , что позволит вам использовать простое решение для цикла.

...