2011-03-07 21 views
15

Supongamos que tengo un iterador:Cómo clonar un iterador?

val it = List("a","b","c").iterator 

Quiero una copia del mismo; mi código es:

val it2 = it.toList.iterator 

Es correcto, pero parece que no es bueno. ¿Hay alguna otra API para hacerlo?

+0

¿Por qué? Una vez que lo hayas clonado, el iterador original se consumirá e inútil, derrotando por completo el punto de un clon en primer lugar ... –

+2

@Kevin, eso no es necesariamente así, ¿no? En abstracto, parece posible tener una operación que me proporcione un iterador que devolverá la misma secuencia que el iterador de origen; por supuesto, problemas de estado pueden hacer que sea imposible para todos los iteradores. No parece requerir inherentemente consumir el de origen. –

+0

Cambiar de 'val' a' def' le daría un nuevo iterador cada vez que haga referencia al símbolo (llamado 'it' en el ejemplo anterior). En muchos casos, esta forma puede parecer más simple. – matanster

Respuesta

9

Advertencia: a partir de Scala 2.9.0, al menos, lo que deja el iterador originales vacía. Puede obtenerval ls = it.toList; val it1 = ls.iterator; val it2 = ls.iteratorpara obtener dos copias. O use duplicate (que también funciona para los que no son de listas).

La respuesta de Rex es por libro, pero de hecho su solución original es de lejos la más eficiente para scala.collection.immutable.List.

Los iteradores de lista se pueden duplicar utilizando ese mecanismo esencialmente sin sobrecarga. Esto se puede confirmar mediante una revisión rápida de la implementación de iterator() en scala.collection.immutable.LinearSeq, esp. la definición del método toList, que simplemente devuelve _.toList del Seq de respaldo que, si es una Lista (como lo es en su caso) es la identidad.

No conocía esta propiedad de los iteradores de listas antes de investigar su pregunta, y estoy muy agradecido por la información ... entre otras cosas, significa que muchos algoritmos de "lista de guijarros" se pueden implementar de manera eficiente sobre Scala Listas inmutables usando Iterators como guijarros.

+0

Desearía poder hacer comentarios favoritos y preguntas, porque plantea un excelente caso/punto de uso. –

+0

publicación relacionada: http: // stackoverflow.com/questions/16380592/spec2-breaks-my-test-data-debido-a-la-forma-funciona-con-iterador – ses

17

El método que está buscando es duplicate.

scala> val it = List("a","b","c").iterator 
it: Iterator[java.lang.String] = non-empty iterator 

scala> val (it1,it2) = it.duplicate 
it1: Iterator[java.lang.String] = non-empty iterator 
it2: Iterator[java.lang.String] = non-empty iterator 

scala> it1.length 
res11: Int = 3 

scala> it2.mkString 
res12: String = abc 
+3

Advertencia: esto utiliza un 'Queue' mutable para almacenar en caché la diferencia entre los iteradores, lo que podría ocasionar problemas de memoria inesperados. Además, 'next' y' hasNext' están 'sincronizados' para los nuevos iteradores, lo que los hace mucho más lentos que los iteradores normales. –

+3

Otra advertencia: ¡Mientras 'it1' y' it2' se pueden usar de forma independiente, al llamar 'it.next' reenvía los dos duplicados! Además, los duplicados comienzan en el elemento actual de 'it', no en el comienzo de la lista. 'duplicate' está especialmente mal documentado, por desgracia. – Raphael

+2

Advertencias concedidas. Son importantes para darse cuenta, pero también son "evidentes" si piensas cuidadosamente sobre lo que estás pidiendo: por supuesto, si tienes un iterador y quieres dos que no están sincronizados, vas a Necesito algún tipo de almacenamiento, solo puedes comenzar donde estás y no volver a un principio perdido, y si no solo vas a copiar todo, entonces necesitarás sincronización para descubrir qué se ha dejado atrás. por ambos iteradores y lo que está listo para agarrar. –