2010-01-25 5 views
11

J'ai des problèmes avec l'écriture d'une application spécifique d'une manière scala-esque et élégante. J'ai essayé depuis un certain temps, mais je ne peux pas trouver une « bonne » solution à ce problème:Itérer sur une liste, retourner le courant, le suivant et l'élément avant le courant

Étant donné que je la liste suivante:

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

Je veux itérer sur cette liste, non seulement en me donnant l'élément courant pour chaque itération mais aussi l'élément avant et après l'élément courant. Cela pourrait être un Tuple3 mais n'est pas nécessaire. Cela pourrait être la signature Tuple:

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

Pour clarifier ce que je veux dire, c'est le Tuple proposé pour chaque itération sur une List[String], qui se termine après le quatrième.

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)

Comment pourrais-je obtenir un tel résultat? Encore une fois: je ne suis pas lié au Tuple3, toute autre solution est également très appréciée!

Merci!

Répondre

16

Voici une approche. Il utilise une nouvelle méthode de collecte 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)) 

Mise à jour: Heres une version qui fonctionne pour les flux.

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

Je suis sûr que cela fonctionne, mais ma version de Scala ne semble pas avoir glissé défini. J'utilise 2.8.0.Beta1-RC7, quelle version est nécessaire d'utiliser glisser? – Malax

+0

J'utilise 2.8.0.Beta1-RC8 – retronym

+0

Semble que RC8 est nécessaire, fonctionne maintenant. Je vous remercie! :-) – Malax

3

Retronym de réponse fonctionne bien si vous utilisez 2.8. Si vous utilisez 2.7.x, il n'y a pas de solution de stock idéale, mais vous pouvez facilement créer la vôtre. Par exemple, si vous ne souhaitez que les triplets où avant et après exister, vous pouvez faire quelque chose comme ceci:

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 vous préférez laisser avant et après rester Options, (edit: Je ne pas vraiment donner un ensemble complet ou sans erreur des modifications avant) puis utiliser à la place

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

Même si j'utilise déjà Scala 2.8, c'est un très bon code pour l'apprentissage. Merci pour cette contribution! – Malax

2

Une meilleure utilisation Scala 2.8 et retronym'ssolution, bien sûr, mais voici ma solution pour 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 
    } 
} 
Questions connexes