我正在编写一个代码,需要生成整数序列的所有组合,这些整数序列在两个其他整数序列的边界内(元素方面)。代码可能比上面的解释更具可读性:
def combinations(startingCounts: List[Int], endingCounts: List[Int] ) = for(
a <- startingCounts(0) to endingCounts(0);
b <- startingCounts(1) to endingCounts(1);
c <- startingCounts(2) to endingCounts(2)
) yield List(a, b, c)
combinations(List(0,7,3), List(1,7,5))
//^returns Vector(List(0, 7, 3), List(0, 7, 4), List(0, 7, 5), List(1, 7, 3), List(1, 7, 4), List(1, 7, 5))
上面的代码按预期工作,但它有两个问题:
我的问题是:实现相同功能的最佳方式是什么,它适用于所有&#34;绑定列表&#34; lenghts?通过&#34; best&#34;我的意思是正确的,simple enough,最好不要比原来慢得多。
答案 0 :(得分:2)
这个怎么样?
def combinations(startingCounts: List[Int], endingCounts: List[Int] ) : IndexedSeq[List[Int]] = {
if(startingCounts.isEmpty)
IndexedSeq(Nil)
else
for{
ns <- combinations(startingCounts.tail, endingCounts.tail)
n <- startingCounts.head to endingCounts.head
} yield
n :: ns
}
答案 1 :(得分:1)
这是我最初的解决方案。它看起来不错,但我想知道它是否可以做得更好。
import scala.annotation.tailrec
type SLInt = IndexedSeq[List[Int]]
def combinations2(startingCounts: List[Int], endingCounts: List[Int] ): SLInt = {
@tailrec
def inner(acc: SLInt, startingCounts: List[Int], endingCounts: List[Int]): SLInt = {
(startingCounts, endingCounts) match {
case (sh :: st, eh :: et) if (sh <= eh) => {
val newAcc = for(
ls <- acc;
last <- (sh to eh)
) yield (last :: ls)
inner(newAcc, st, et)
}
case (Nil, Nil) => acc
case _ => throw new IllegalArgumentException()
}
}
inner(IndexedSeq(List()), startingCounts.reverse, endingCounts.reverse)
}
combinations2(List(0,7,3), List(1,7,5))
//res3: SLInt = Vector(List(0, 7, 3), List(1, 7, 3), List(0, 7, 4), List(1, 7, 4), List(0, 7, 5), List(1, 7, 5))
结果的顺序不同,但这没有什么区别。我正在执行List.reverse
以避免使用List
追加操作并改为使用前置,这应该是常量时间。