Reputation: 123
I have the need to combine values from several (possibly infinite) streams, the number of streams may vary; sometimes to "draw one from each" and handle them as a tuple, sometimes to interleave the values.
Sample input could be like this:
val as= Stream.from(0)
val bs= Stream.from(10)
val cs= Stream.from(100)
val ds= Stream.from(1000)
val list= List(as, bs, cs, ds)
For the first use case, I would like to end up with something like
Seq(0, 10, 100, 1000), Seq(1, 11, 101, 1001), ...
and for the second
Seq(0, 10, 100, 1000, 1, 11, 101, 1001, ...
Is there a standard, or even built-in, solution for combining Stream
s?
Upvotes: 1
Views: 1605
Reputation: 56
My solution is identical to the solution from Eastsun but easier to understand:
def combine[A](s:Seq[Stream[A]]):Stream[Seq[A]]=s.map(_.head) #:: combine(s.map(_.tail))
Upvotes: 4
Reputation: 18859
Here it is:
scala> val coms = Stream.iterate(list)(_ map (_.tail)) map (_ map (_.head))
coms: scala.collection.immutable.Stream[List[Int]] = Stream(List(0, 10, 100, 1000), ?)
scala> coms take 5 foreach println
List(0, 10, 100, 1000)
List(1, 11, 101, 1001)
List(2, 12, 102, 1002)
List(3, 13, 103, 1003)
List(4, 14, 104, 1004)
scala> val flat = coms.flatten
flat: scala.collection.immutable.Stream[Int] = Stream(0, ?)
scala> flat take 12 toList
res1: List[Int] = List(0, 10, 100, 1000, 1, 11, 101, 1001, 2, 12, 102, 1002)
Upvotes: 1
Reputation: 123
The best I have come up with yet looks a bit "crowded", as if I'm trying to write a textbook example of stream operations...
def combine[A](list: List[Stream[A]]): Stream[Seq[A]] = {
val listOfSeqs= list.map(_.map(Seq(_))) // easier to reduce when everything are Seqs...
listOfSeqs.reduceLeft((stream1, stream2)=> stream1 zip stream2 map {
case (seq1, seq2) => seq1 ++ seq2
})
}
def interleave[A](list: List[Stream[A]]): Stream[A] = combine(list).flatten
Upvotes: 0