Загляните вперед при итерации массива в PHP
Вопрос
Можно ли «заглянуть вперед» при переборе массива в PHP 5.2?Например, я часто использую foreach для манипулирования данными из массива:
foreach($array as $object) {
// do something
}
Но мне часто нужно взглянуть на следующий элемент при просмотре массива.Я знаю, что мог бы использовать for
цикл и ссылаемся на следующий элемент по его индексу ($array[$i+1]
), но для ассоциативных массивов это не сработает.Есть ли какое-нибудь элегантное решение моей проблемы, возможно, с использованием SPL?
Решение
Вы можете использовать Итератор кэширования для этой цели.
Вот пример:
$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
в качестве второго параметра конструктора.
Кстати, CachingIterator получил свое название благодаря способности кэшировать все результаты, которые он обработал до сих пор.Чтобы это работало, вам нужно создать его экземпляр с помощью CachingIterator::FULL_CACHE
а затем вы можете получить кэшированные результаты с помощью getCache()
.
Другие советы
Использовать array_keys
.
$keys = array_keys($array);
for ($i = 0; $i < count($keys); $i++) {
$cur = $array[$keys[$i]];
$next = $array[$keys[$i+1]];
}
Вы можете использовать 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);
}
Я знаю, что это старый пост, но теперь я могу лучше объяснить текущую/следующую/предыдущую вещь.Пример:
$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
Я знаю, что могу использовать цикл for и ссылаться на следующий элемент по его индексу ($array[$i+1]), но для ассоциативных массивов это не сработает.
Рассмотрите возможность преобразования вашего ассоциативного массива в последовательно индексированный с помощью array_values(), что позволяет использовать простое решение цикла for.