2010-03-16 11 views
28

¿Es posible "mirar hacia adelante" mientras se itera una matriz en PHP 5.2? Por ejemplo, a menudo uso foreach para manipular datos de una matriz:Mire hacia adelante cuando itere una matriz en PHP

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

Pero a menudo necesito echar un vistazo al siguiente elemento, mientras que ir a través de la matriz. Sé que podría usar un bucle for y hacer referencia al siguiente elemento por su índice ($array[$i+1]), pero no funcionaría para matrices asociativas. ¿Hay alguna solución elegante para mi problema, tal vez con SPL?

Respuesta

48

Puede utilizar el CachingIterator para este propósito.

Aquí se muestra un ejemplo:

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

El CachingIterator es siempre un paso por detrás del iterador interno:

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

Por lo tanto, cuando se hace foreach sobre $collection, el elemento actual de la ArrayIterator interior será el siguiente elemento ya, lo que le permite echarle un vistazo:

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

salida será:

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

Por alguna razón que no puedo explicar, la CachingIterator siempre tratará de convertir el elemento actual de la cadena. Si desea iterar sobre una colección de objetos y necesita acceder a las propiedades y métodos, pase CachingIterator::TOSTRING_USE_CURRENT como el segundo parámetro para el constructor.


En una nota, la CachingIterator recibe su nombre de la capacidad de almacenar en caché todos los resultados que ha repiten a lo largo hasta el momento. Para que esto funcione, debe crear una instancia con CachingIterator::FULL_CACHE y luego puede obtener los resultados almacenados en caché con getCache().

+1

+1 Ni siquiera sabía que estos ([x] Iteradores) existían, muy útiles, especialmente el DirectoryIterator.Eso me va a ahorrar una gran cantidad de trabajo la próxima vez que haga cosas de archivos. Gracias :) – Psytronic

+2

@Psytronic son muy bonitos. La capacidad de apilar permite cosas muy interesantes y flexibles. Lamentablemente, no está bien documentado, pero consulte http://www.phpro.org/tutorials/Introduction-to-SPL.html – Gordon

+0

Desafortunadamente, la solución no funciona si la matriz contiene objetos y no cadenas. Obtengo la siguiente excepción: 'Error fatal capturable: el objeto de la clase MySampleClass no se pudo convertir a cadena en /home/www/test.php en la línea 398' – pako

6

Puede usar next y prev para iterar una matriz. current devuelve el valor actual de los elementos y key la clave actual.

Por lo que podría hacer algo como esto:

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

    // … 

    next($array); 
} 
+2

El código parece bastante complicado, y es propenso a errores (demasiados "nexts/prevs" y pueden ocurrir cosas muy extrañas ...). – pako

17

Use array_keys.

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

¿Por qué tomaría todas las complicaciones de la respuesta aceptada para hacer algo tan básico, cuando la respuesta está ahí en las funciones centrales? Gracias. – Noumenon

+0

Me gusta esta respuesta, hay muchas ventajas de poder referirme a elementos numéricamente. –

3

Sé que esta es una publicación anterior, pero ahora puedo explicar mejor la anterior/siguiente/anterior. Ejemplo:

$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

Creo que esto no se informará correctamente si hay valores falsy en $ array. – 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.

considerar convertir su matriz asociativa en una manera secuencial indexado uno con array_values(), lo que permite utilizar el simple para solución bucle.

Cuestiones relacionadas