2010-01-25 7 views
11

Ich habe Probleme mit dem Schreiben einer bestimmten Anwendung auf eine skalare und elegante Weise. Ich habe versucht, das nun schon seit einiger Zeit, aber ich kann eine „gute“ Lösung für dieses Problem nicht finden:Iterieren über eine Liste, Rückgabe der aktuellen, nächsten und das Element vor aktuellen

Da ich die folgende Liste habe:

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

Ich möchte über diese Liste iterieren, nicht nur Ich gebe das aktuelle Element für jede Iteration, aber auch das Element vor und nach dem aktuellen Element. Dies könnte ein Tuple3 sein, ist aber nicht erforderlich. Dies könnte die Tuple-Signatur:

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

Um zu klären, was ich meine, das ist die vorgeschlagene Tuple für jede Iteration über ein List[String], nach dem vierten Ende.

Iteration 1: (None, "foo", Some("bar"))

Iteration 2: (Some("foo"), "bar", Some("baz"))

Iteration 3: (Some("bar"), "baz", Some("blah"))

Iteration 4: (Some("baz"), "blah", None)

Wie konnte ich erreichen, ein solches Ergebnis? Nochmals: Ich bin nicht an den Tuple3 gebunden, jede andere Lösung wird auch sehr geschätzt!

Danke!

Antwort

16

Hier ist ein Ansatz. Es verwendet eine neue Scala 2.8 Sammelmethode 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)) 

aktualisieren: Heres eine Version, die für Streams funktioniert.

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

Ich bin mir sicher, dass das funktioniert, aber meine Version von Scala scheint nicht gleitend definiert zu sein. Ich benutze 2.8.0.Beta1-RC7, welche Version wird benötigt, um gleiten zu können? – Malax

+0

Ich benutze 2.8.0.Beta1-RC8 – retronym

+0

Scheint, dass RC8 erforderlich ist, funktioniert jetzt. Vielen Dank! :-) – Malax

3

Retronym ‚s Antwort funktioniert gut, wenn Sie 2.8 verwenden sind. Wenn Sie 2.7.x verwenden, gibt es keine großartige Standardlösung, aber Sie können Ihre eigenen einfach erstellen. Zum Beispiel, wenn Sie nur verdreifacht wollen, wo vor und nach existieren, können Sie etwas tun:

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) 

Wenn Sie es vorziehen, vor und nach, damit Optionen bleiben, (edit: ich nicht wirklich geben vollständiger oder fehlerfrei vor den Änderungen eingestellt) anstelle dann verwenden

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

Auch wenn ich Scala 2.8 bereits benutze, ist dies ein sehr schöner Code zum Lernen. Danke für diesen Beitrag! – Malax

2

Bessere Nutzung Scala 2.8 und retronym'ssolution, natürlich, aber hier ist meine Lösung für 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 
    } 
} 
Verwandte Themen