Hi @Sciss,
I had a first stab at using foldM:
import cats.implicits.*
def combine(xss: List[List[String]]): List[List[String]] =
xss.foldM(List(List.empty[String])){(yss,xs) =>
for
x <- xs
ys <- yss
yield List(x :: ys)
}.flatten.map(_.reverse)
val xss2 = List(List("a", "b"), List("c", "d", "e"))
val yss2 = combine(xss2)
assert(yss2 == List(
List("a", "c"), List("a", "d"), List("a", "e"),
List("b", "c"), List("b", "d"), List("b", "e")
))
val xss3 = List(List("a", "b"), List("c", "d", "e"), List("f", "g"))
val yss3 = combine(xss3)
assert(yss3 == List(
List("a", "c", "f"), List("a", "c", "g"),
List("a", "d", "f"), List("a", "d", "g"),
List("a", "e", "f"), List("a", "e", "g"),
List("b", "c", "f"), List("b", "c", "g"),
List("b", "d", "f"), List("b", "d", "g"),
List("b", "e", "f"), List("b", "e", "g")
))
val xss4 = List(List("a", "b"), List("c", "d", "e"), List("f", "g"), List("h", "i"))
val yss4 = combine(xss4)
assert(yss4 == List(
List("a", "c", "f", "h"), List("a", "c", "f", "i"),
List("a", "c", "g", "h"), List("a", "c", "g", "i"),
List("a", "d", "f", "h"), List("a", "d", "f", "i"),
List("a", "d", "g", "h"), List("a", "d", "g", "i"),
List("a", "e", "f", "h"), List("a", "e", "f", "i"),
List("a", "e", "g", "h"), List("a", "e", "g", "i"),
List("b", "c", "f", "h"), List("b", "c", "f", "i"),
List("b", "c", "g", "h"), List("b", "c", "g", "i"),
List("b", "d", "f", "h"), List("b", "d", "f", "i"),
List("b", "d", "g", "h"), List("b", "d", "g", "i"),
List("b", "e", "f", "h"), List("b", "e", "f", "i"),
List("b", "e", "g", "h"), List("b", "e", "g", "i")
))
Here is a scastie.
If you are new to foldM (I am not making any assumptions) and you are interested, maybe check out the following:
Combinatorial Interview Problems with Backtracking Solutions - from Procedural to Functional Programming - Part 2