2010-07-15 29 views
12

Ho bisogno di scorrere attraverso un elenco ma modo circolare. Ho anche bisogno di aggiungere nuovi elementi alla lista e scorrere tutti gli elementi (vecchi e nuovi elementi), come faccio? C'è qualche struttura dati per loro?Iterating circular way

risposta

7

Penso che forse questo è quello che vuoi; la possibilità di aggiungere nuovi elementi alla tua lista anche mentre la stai iterando. Il codice è brutto ma sembra funzionare.

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 

} 

Si può usare in questo modo:

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

Una possibilità è quella di utilizzare la classe Stream per creare un pigro, circolare, sequenza infinita:

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) 

o in questo modo:

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

i flussi sono infiniti, ma non sono circolari. Per renderli circolari è necessario un trucco come 'def circular [T] (xs: Stream [T]): Stream [T] = {lazy val knot: Stream [T] = xs # ::: knot; knot} ' –

7

Questo genere di cose merita davvero di essere nella norma libreria di flusso, ma non sembra essere. La risposta di dbryne con un flusso funziona bene, o se preferite in for-comprensione forma

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

Il primo generatore di flusso mantiene le cose andare per sempre, anche se si sta ignorando il valore. Il secondo generatore viene implicitamente appiattito nel flusso infinito desiderato.

+1

Non hai bisogno di un argomento per' Stream.continually() ', penso che l'uso di un 'Stream [Unit]' sembra un po' meno confuso di un 'Stream [Int] '. – Debilski

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

Nota questo è infinito, ma non circolare. –