lre
lre

Reputation: 123

Combining Scala streams

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 Streams?

Upvotes: 1

Views: 1605

Answers (3)

Anran Wang
Anran Wang

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

Eastsun
Eastsun

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

lre
lre

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

Related Questions