I need iterate through a List but circular way. I need too add new elements to the list and iterate over all elements (olds and news elements), How I do it? Is there any data structure for them?
+8
A:
One option is to use the Stream
class to create a lazy, circular, infinite sequence:
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)
or this way:
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
dbyrne
2010-07-15 14:03:16
As a side note, in clojure you can do this quite succinctly: `(take 9 (cycle '(1 2 3)))`
dbyrne
2010-07-15 16:56:47
+4
A:
This sort of thing really deserves to be in standard stream library, but doesn't appear to be. dbryne's answer with a stream works well, or if you prefer it in for-comprehension form
val listToRepeat:List[Foo]
val forever:Stream[Foo] = for(x<-Stream.continually(1); y<-listToRepeat) yield y
The first stream generator keeps things going forever even though you are ignoring the value. The second generator gets implicitly flattened into the infinite stream you want.
Dave Griffith
2010-07-15 15:47:21
You don’t need an argument for `Stream.continually()`, i think using a `Stream[Unit]` looks a little less confusing than a `Stream[Int]`.
Debilski
2010-07-15 23:31:12
+4
A:
I think maybe this is what you want; the ability to add new elements to your list even as you are iterating it. The code is ugly but it seems to work.
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
}
You can use it like this:
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)
Magnus
2010-07-15 22:25:54