Idiomatic Scala way to generate combinations lazily

I want to create a combination of some values, as in the code below:

object ContinueGenerate { val foods = List("A", "B", "C") val places = List("P1", "P2", "P3") val communities = List("C1", "C2", "C3", "C4") case class Combination(food: String, place: String, community: String) def allCombinations() = { for { food <- foods; place <- places; community <- communities } yield Combination(food, place, community) } def main(args: Array[String]) { allCombinations foreach println } } 

However, the problem with this approach is that all data is generated immediately. This is a big problem when the size of foods , places and communities becomes very large. There may also be other parameters besides these three.

Therefore, I want to be able to generate combinations in a continuation style, so that a combination is only created when it is requested.

What would be the idiomatic way for Scala to do this?

+7
scala combinations
source share
2 answers

You can do this by using View on each list. In the code below, I added a side effect so that it displays when yield called for each item.

 val foods = List("A", "B", "C") val places = List("P1", "P2", "P3") val communities = List("C1", "C2", "C3", "C4") case class Combination(food: String, place: String, community: String) def allCombinations() = for { food <- foods; place <- places; community <- communities } yield { val comb = Combination(food, place, community) println(comb) comb } //Prints all items val combinations = allCombinations() def allCombinationsView() = for { //Use a view of each list food <- foods.view; place <- places.view; community <- communities.view } yield { val comb = Combination(food, place, community) println(comb) comb } //Prints nothing val combinationsView = allCombinationsView() //Prints 5 items val five = combinationsView.take(5).toList 
+4
source share

You are using threads:

 object ContinueGenerate { val foods = Stream("A", "B", "C") val places = Stream("P1", "P2", "P3") val communities = Stream("C1", "C2", "C3", "C4") case class Combination(food: String, place: String, community: String) def allCombinations() = { for { food <- foods; place <- places; community <- communities } yield Combination(food, place, community) } def main(args: Array[String]) { allCombinations foreach println } } 

A Stream caches all data. If you only want to iterate once, use an Iterator instead, which should collect the trash of the elements that have already been traversed.

+7
source share

All Articles