2010-01-25 10 views
11

Tengo problemas para escribir una aplicación específica a la manera scala-elegante. He intentado esto desde hace algún tiempo, pero no puedo encontrar una "buena" solución a este problema:Itere sobre una lista, devolviendo el actual, el siguiente y el elemento antes del actual

Dado que tengo la siguiente lista:

List("foo", "bar", "baz", "blah") 

Quiero iterar sobre esta lista, no sólo dándome el elemento actual para cada iteración pero también el elemento antes y después del elemento actual. Esto podría ser un Tuple3 pero no es obligatorio. Esto podría ser la firma de tupla:

(Option[T], T, Option[T]) 

Para aclarar lo que quiero decir, esta es la tupla propuesto para cada iteración sobre un List[String], que termina después del cuarto.

iteración 1: (None, "foo", Some("bar"))

iteración 2: (Some("foo"), "bar", Some("baz"))

iteración 3: (Some("bar"), "baz", Some("blah"))

iteración 4: (Some("baz"), "blah", None)

¿Cómo podría lograr tal resultado? De nuevo: no estoy vinculado al Tuple3, ¡cualquier otra solución también es muy apreciada!

Gracias!

Respuesta

16

Aquí hay un enfoque. Utiliza un nuevo método de recolección Scala 2.8 sliding.

def window[A](l: List[A]): Iterator[List[Option[A]]] = 
    (None :: l.map(Some(_)) ::: List(None)) sliding 3 

window(List(1, 2, 3, 4, 5)).toList 

// List(List(None, Some(1), Some(2)), List(Some(1), Some(2), Some(3)), List(Some(2), Some(3), Some(4)), List(Some(3), Some(4), Some(5)), List(Some(4), Some(5), None)) 

actualización: Aquí está una versión que funciona con flujos.

def windowS[A](s: Stream[A]): Stream[List[Option[A]]] = 
    (None #:: s.map(Some(_): Option[A]) #::: Stream(None: Option[A])).sliding(3).toStream.map(_.toList) 

val posInts = Stream.range(1, Integer.MAX_VALUE) 
windowS(posInts).take(5).toList 
+0

Estoy seguro de que esto funciona, pero mi versión de Scala no parece tener deslizamiento definido. Estoy usando 2.8.0.Beta1-RC7, ¿qué versión se requiere para usar deslizamiento? – Malax

+0

Estoy usando 2.8.0.Beta1-RC8 – retronym

+0

Parece que RC8 es obligatorio, funciona ahora. ¡Gracias! :-) – Malax

3

Retronym 's respuesta funciona bien si está utilizando 2.8. Si está utilizando 2.7.x, no hay una gran solución de stock, pero puede construir la suya fácilmente. Por ejemplo, si desea que sólo se triplica donde antes y después de existir, se puede hacer algo como esto:

class Tuple3Iterator[T](solo: Iterator[T]) extends Iterator[(T,T,T)] { 
    var current = if (solo.hasNext) Some(solo.next) else None 
    var future = if (solo.hasNext) Some(solo.next) else None 
    def hasNext = solo.hasNext 
    def next = { 
    val past = current 
    current = future 
    future = Some(solo.next) 
    (past.get,current.get,future.get) 
    } 
} 
class IteratorToT3[T](it: Iterator[T]) { 
    def treble = new Tuple3Iterator[T](it) 
} 
implicit def allowTrebling[T](it: Iterable[T]) = new IteratorToT3[T](it.elements) 

scala> List("Hi","there",5,"you").treble.foreach(println(_))   
(Hi,there,5) 
(there,5,you) 

Si prefiere permitir que antes y después de permanecer opciones, (edit: Yo realmente no dan una completa o libre de errores conjunto de cambios antes), entonces en lugar de utilizar

class Tuple3Iterator[T](solo: Iterator[T]) extends Iterator[(Option[T],T,Option[T])] { 
    var current = None:Option[T] 
    var future = if (solo.hasNext) Some(solo.next) else None 
    def hasNext = (solo.hasNext || future!=None) 
    def next = { 
    val past = current 
    current = future 
    future = if (solo.hasNext) Some(solo.next) else None 
    (past,current.get,future) 
    } 
} 

scala> List("Hi","there",5,"you").treble.foreach(println(_)) 
(None,Hi,Some(there)) 
(Some(Hi),there,Some(5)) 
(Some(there),5,Some(you)) 
(Some(5),you,None) 
+0

Incluso si ya estoy usando Scala 2.8, este es un buen código para aprender. ¡Gracias por esta contribución! – Malax

2

Mejor uso Scala 2.8 y retronym'ssolution, por supuesto, pero aquí es mi solución para Scala 2.7:

class MyIterator[T](l: List[T]) extends Iterator[(Option[T],T,Option[T])] { 
    var last: Option[T] = None 
    var curr = l 
    def hasNext = !curr.isEmpty 
    def next = { 
    val t = curr match { 
     case first :: second :: tail => (last, first, Some(second)) 
     case first :: Nil => (last, first, None) 
     case Nil => throw new java.util.NoSuchElementException 
    } 
    last = Some(curr.head) 
    curr = curr.tail 
    t 
    } 
} 
Cuestiones relacionadas