Как упоминалось в моем комментарии (выше), я нашел несколько разных способов разрешения конфликта типов, но не таким образом, чтобы получить желаемые результаты.
def combinations(occurrences: List[(Char,Int)]): List[List[(Char,Int)]] = {
val curr = occurrences filter { case (c,o) => o != 0 }
if (curr.isEmpty) List(List())
else {
val result = for {
(c, o) <- curr
res <- combinations(curr.updated(curr.indexOf((c, o)), (c, o-1)))
// using occurrences here ^^^^ tends to StackOverflow
} yield res
curr :: result
}
}
def combinations(occurrences: List[(Char,Int)]): List[List[(Char,Int)]] = {
val curr = occurrences filter { case (c,o) => o != 0 }
if (curr.isEmpty)
List(List()) // or Nil for a different wrong result
else {
val result = curr.flatMap { case (c, o) =>
combinations(curr.updated(curr.indexOf((c, o)), (c, o-1)))
}
curr :: result
}
}
Вот другой подход (который, кажется, действительно работает).
def crossProd[T](in: Seq[T]*): Seq[Seq[T]] =
if (in.isEmpty) in
else in.tail.foldLeft(in.head.map(Seq(_))) {
for {sentence <- _; word <- _} yield sentence :+ word
}
def combinations(occurrences: List[(Char,Int)]) : List[List[(Char,Int)]] =
crossProd(occurrences.map{case (c,n) => (0 to n).map(x => (c,x))}:_*)
.map(_.filter(_._2 > 0).toList)
.toList
тестирование:
combinations(List(('c',2),('x',3),('#',1)))
//res0: List[List[(Char, Int)]] =
// List(List()
// , List((#,1))
// , List((x,1))
// , List((x,1), (#,1))
// , List((x,2))
// , List((x,2), (#,1))
// , List((x,3))
// , List((x,3), (#,1))
// , List((c,1))
// , List((c,1), (#,1))
// , List((c,1), (x,1))
// , List((c,1), (x,1), (#,1))
// , List((c,1), (x,2))
// , List((c,1), (x,2), (#,1))
// , List((c,1), (x,3))
// , List((c,1), (x,3), (#,1))
// , List((c,2))
// , List((c,2), (#,1))
// , List((c,2), (x,1))
// , List((c,2), (x,1), (#,1))
// , List((c,2), (x,2))
// , List((c,2), (x,2), (#,1))
// , List((c,2), (x,3))
// , List((c,2), (x,3), (#,1)))