Lazy decision to collapse according to the Stream algorithm (to take K elements from the result, only Q elements from the input should be consumed)

There is an interesting problem with some colleagues, and I came up with and discussing, and I can’t bow my head to a lazy solution. There is one?

It came while studying functional programming, and we thought about expanding a simple task in terms of a lazy solution

First I will talk about a lazy problem (to which we found an easy fold + flatMap solution)

Say we have a word. Tue

We want to generate all subsets of a word such that:

For "abcd", the result will be:
"," a "," b "," ab "," c "," ac "," bc "," abc "," d "," ad "," bd "," abd "," cd "," acd "," bcd "," abcd "

Basically go char for char and compose the result so far with the current char, always doubling the result.

Question:

Is there a lazy solution to this problem?

Considering:

  • input as a char stream

  • expected result Stream of Strings

Can we consume the input stream lazily, having enough data to create only the number of results that we need

Here is my solution so far in Scala:

import org.scalatest.{FreeSpec, Matchers}

class Problem extends FreeSpec with Matchers {

  private def solution(word: Stream[Char]) = foldr(compose, Stream(""))(word)

  def compose(letter: Char, results: => Stream[String]): Stream[String] = {
    results append results.map(word => word + letter)
  }

  def foldr[A, B](combine: (A, =>B) => B, base: B)(xs: Stream[A]): B =
    if (xs.isEmpty) base
    else
      combine(xs.head, foldr(combine, base)(xs.tail))

  "Problem" - {

    "Taking 5 elements from the result should evaluate only 3 elements from the initial stream" in {
      solution(
        Stream('a', 'b', 'c', 'd', 'e', 'f').map(
          x => {
            println(s"Applying map on element: '$x'")
            x
          }
        )
      ).take(5).toList shouldBe List("", "f", "e", "fe", "d")
    }
  }

}

I used the foldr implementation from blogpost , as I understand it, Scala thread is not lazy foldRight?

, , , ,

Applying map on element: 'a'
Applying map on element: 'b'
Applying map on element: 'c'
Applying map on element: 'd'
Applying map on element: 'e'
Applying map on element: 'f'

Stream


, , :

import org.scalatest.{FreeSpec, Matchers}

class Problem extends FreeSpec with Matchers {

  private def solution(word: Stream[Char]) = word.foldRight(Stream("")) (add)

  def add(letter: Char, results: Stream[String]): Stream[String] = results.flatMap(result =>  {
    println(s"Composing result '$result' with letter: '$letter'")
    Stream(result, letter + result)
  })

  "Problem" - {

    "Taking 5 elements from the result should evaluate only 3 elements from the initial stream" in {
      solution(
        Stream('a', 'b', 'c', 'd', 'e', 'f').map(
          x => {
            println(s"Applying map on element: '$x'")
            x
          }
        )
      ).take(5).toList shouldBe List("", "a", "b", "ab", "c")
    }
  }
}

:

Applying map on element: 'a'
Applying map on element: 'b'
Applying map on element: 'c'
Applying map on element: 'd'
Applying map on element: 'e'
Applying map on element: 'f'
Composing result '' with letter: 'f'
Composing result '' with letter: 'e'
Composing result '' with letter: 'd'
Composing result '' with letter: 'c'
Composing result '' with letter: 'b'
Composing result '' with letter: 'a'
Composing result 'b' with letter: 'a'
Composing result 'c' with letter: 'b'
Composing result 'c' with letter: 'a'

, . . !


Archetypal Paul

  private def solution(word: Stream[Char]) =
    word.scanLeft((Stream(""), Stream(""))) ((acc, l)=> {
      val r = acc._2.map(_ + l)
      (r, acc._2 append r)
    }).flatMap(_._1)
+4
1

:

val zs= Stream('a','b','c','d')
zs.map( x => {println(s"Applying map on element: '$x'"); x})
  .scanLeft("")((a, b) => a :+ b)
  .flatMap(_.permutations)
  .take(4).toList
  //> Applying map on element: 'a'
  //| Applying map on element: 'b'
  //| Applying map on element: 'c'
  //| res1: List[String] = List("", a, ab, ba)

, (take(5) d), .

+2

All Articles