Jonathan Chow
Jonathan Chow

Reputation: 105

In Scala, create a stream based on previous value and a second stream

I can't come up with a way to combine these into a single stream. I have:

val loop: Stream[Bar] = Stream(bar1, bar2, bar3) #::: loop
val init: Foo = new Foo()
def nextFoo(foo: Foo, bar: Bar): Foo = { ... }

What I want is a stream like this:

Stream(
    init, 
    nextFoo(init, bar1), 
    nextFoo(nextFoo(init, bar1), bar2),
    nextFoo(nextFoo(nextFoo(init, bar1), bar2), bar3),
    nextFoo(nextFoo(nextFoo(nextFoo(init, bar1), bar2), bar3), bar1),
    ...
)

or, in words, each element depends on the next element in loop and the previous element in my output stream.

It's a chicken-and-egg problem - I feel like I want to zip the second stream with the first one but I can't create the first stream (e.g., with Stream.iterate) without zipping on the second.

Is this possible with just the functions in Scala's collections library? I could probably put something together with (new Iterator { ... }).toStream but would want to avoid that if possible.

Upvotes: 2

Views: 1004

Answers (1)

Eugene Zhulenev
Eugene Zhulenev

Reputation: 9734

With "fake" Bar and Foo that will contains list of "processed" bars it will look like this:

  case class Bar(s: String)
  val bar1 = Bar("bar1")
  val bar2 = Bar("bar2")
  val bar3 = Bar("bar3")

  case class Foo(bars: Seq[Bar])


  val loop: Stream[Bar] = Stream(bar1, bar2, bar3) #::: loop
  val init: Foo = new Foo(Nil)
  def nextFoo(foo: Foo, bar: Bar): Foo =
    foo.copy(bars = foo.bars :+ bar)

  val foos: Stream[Foo] = Stream(init) #::: foos.zip(loop).map({ case (f, b) => nextFoo(f, b) })

  foos.take(10).toList.foreach(println)

Result:

Foo(List())
Foo(List(Bar(bar1)))
Foo(List(Bar(bar1), Bar(bar2)))
Foo(List(Bar(bar1), Bar(bar2), Bar(bar3)))
Foo(List(Bar(bar1), Bar(bar2), Bar(bar3), Bar(bar1)))
Foo(List(Bar(bar1), Bar(bar2), Bar(bar3), Bar(bar1), Bar(bar2)))
Foo(List(Bar(bar1), Bar(bar2), Bar(bar3), Bar(bar1), Bar(bar2), Bar(bar3)))
Foo(List(Bar(bar1), Bar(bar2), Bar(bar3), Bar(bar1), Bar(bar2), Bar(bar3), Bar(bar1)))
Foo(List(Bar(bar1), Bar(bar2), Bar(bar3), Bar(bar1), Bar(bar2), Bar(bar3), Bar(bar1), Bar(bar2)))
Foo(List(Bar(bar1), Bar(bar2), Bar(bar3), Bar(bar1), Bar(bar2), Bar(bar3), Bar(bar1), Bar(bar2), Bar(bar3)))

Upvotes: 2

Related Questions