2010-03-16 3 views
28

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

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

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

ответ

48

Вы можете использовать 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 в качестве второго параметра в конструктор.


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

+1

+1 Даже не знал, что эти ([x] итераторы) существуют, очень полезны, espec the DirectoryIterator.Это спасет меня от загрузки большого объема работы в следующий раз, когда я делаю файлы. Спасибо :) – Psytronic

+2

@Psytronic они действительно опрятные. Возможность складывать их позволяет очень классно и гибко. К сожалению, документы плохо документированы, но посмотрите http://www.phpro.org/tutorials/Introduction-to-SPL.html – Gordon

+0

К сожалению, решение не работает, если массив содержит объекты, а не строки. Я получаю следующее исключение: 'Catchable fatal error: Объект класса MySampleClass не может быть преобразован в строку в /home/www/test.php в строке 398' – pako

6

Вы можете использовать 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); 
} 
+2

Код выглядит довольно сложным, и он подвержен ошибкам (слишком много «nexts/prevs», и могут произойти очень странные вещи ...). – pako

17

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

$keys = array_keys($array); 
for ($i = 0; $i < count($keys); $i++) { 
    $cur = $array[$keys[$i]]; 
    $next = $array[$keys[$i+1]]; 
} 
+0

Почему я должен принять все усложнение принятого ответа, чтобы сделать такую ​​основную вещь, когда ответ прямо там в основных функциях? Спасибо. – Noumenon

+0

Мне нравится этот ответ, есть много преимуществ, чтобы иметь возможность ссылаться на элементы численно. –

3

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

$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

Я думаю, что это не сообщит правильно, если есть значения фальши в $ массиве. – grantwparks

0

I know I could use a for loop and reference the next item by its index ($array[$i+1]), but it wouldn't work for associative arrays.

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

Смежные вопросы