2010-07-15 7 views
12

J'ai besoin d'itérer à travers une liste mais de façon circulaire. J'ai aussi besoin d'ajouter de nouveaux éléments à la liste et de parcourir tous les éléments (les anciens et les éléments d'information), comment je le fais? Y a-t-il une structure de données pour eux?Itération de manière circulaire

Répondre

7

Je pense que c'est peut-être ce que vous voulez; la possibilité d'ajouter de nouveaux éléments à votre liste même si vous l'itérez. Le code est moche mais ça a l'air de marcher.

import scala.collection.mutable.Queue 

class Circular[A](list: Seq[A]) extends Iterator[A]{ 

    val elements = new Queue[A] ++= list 
    var pos = 0 

    def next = { 
    if (pos == elements.length) 
     pos = 0 
    val value = elements(pos) 
    pos = pos + 1 
    value 
    } 

    def hasNext = !elements.isEmpty 
    def add(a: A): Unit = { elements += a } 
    override def toString = elements.toString 

} 

Vous pouvez l'utiliser comme ceci:

scala> var circ = new Circular(List(1,2)) 
res26: Circular[Int] = Queue(1,2) 
scala> circ.next 
res27: Int = 1 
scala> circ.next 
res28: Int = 2 
scala> circ.next 
res29: Int = 1 
scala> circ.add(5) 
scala> circ.next 
res30: Int = 2 
scala> circ.next 
res31: Int = 5 
scala> circ 
res32: Circular[Int] = Queue(1,2,5) 
17

Une option consiste à utiliser la classe Stream pour créer une séquence paresseuse, circulaire, infinie:

scala> val values = List(1, 2, 3) 
values: List[Int] = List(1, 2, 3) 

scala> Stream.continually(values.toStream).flatten.take(9).toList 
res2: List[Int] = List(1, 2, 3, 1, 2, 3, 1, 2, 3) 

ou de cette façon:

val values = List(1, 2, 3) 

def circularStream(values: List[Int], 
        remaining: List[Int] = List()): Stream[Int] = { 

    if (remaining.isEmpty) 
    circularStream(values,values) 
    else 
    Stream.cons(remaining.head, circularStream(values, remaining.drop(1))) 
} 

circularStream(values).take(9).toList //Same result as example #1 
+6

Vos cours d'eau sont infinies, mais ils ne sont pas circulaires. Pour les rendre circulaires, vous avez besoin d'un truc comme 'def circulaire [T] (xs: Stream [T]): Stream [T] = {noeud valse paresseux: Stream [T] = xs # ::: noeud; knot} ' –

7

Ce genre de chose mérite vraiment d'être dans la norme bibliothèque de flux, mais ne semble pas être. La réponse de dbryne avec un jet fonctionne bien, ou si vous préférez dans la compréhension de-forme

val listToRepeat:List[Foo] 
val forever:Stream[Foo] = for(x<-Stream.continually(1); y<-listToRepeat) yield y 

Le premier générateur de flux garde les choses vont pour toujours, même si vous ignorez la valeur. Le deuxième générateur est implicitement aplati dans le flux infini que vous voulez.

+1

Vous n'avez pas besoin d'argument pour' Stream.continually() ', je pense que l'utilisation d'un' Stream [Unit] 'semble un peu moins confuse qu'un' Stream [Int] '. – Debilski

10
def forever:Stream[Int] = Stream(1,2,3) append forever 
+2

Notez que ceci est infini, mais pas circulaire. –