Scala 自定义组合函数
self defined combination function in Scala
我想在scala中实现一个组合函数,我的代码如下:
def combination[A](n: Int, ls: List[A]): List[List[A]] ={
(n, ls) match{
case (_, Nil) => List(Nil)
case (1, _) => ls.map(List(_))
case (_, _) if n > ls.size => List.empty
case _ => ls.flatMap(x => combination(n - 1, subList(x, ls)).map(x :: _))
}
}
def subList[A](e: A, in: List[A]) = in.takeRight(in.size - in.indexOf(e) - 1)
但结果不是我所期望的。当我打电话给 combination(3, List('a, 'b, 'c, 'd, 'e, 'f)
时。它会给我那些带有一个或两个元素的结果,比如 List('d, 'f), List('f) 等等。谁能帮我找到问题所在?谢谢
更新:
正确的版本是
def combination[A](n: Int, ls: List[A]): List[List[A]] ={
(n, ls) match{
case (_, Nil) => Nil
case (1, _) => ls.map(List(_))
case (_, _) if n > ls.size => Nil
case _ => ls.flatMap(x => combination(n - 1, subList(x, ls)).map(x :: _))
}
}
def subList[A](e: A, in: List[A]) = in.takeRight(in.size - in.indexOf(e) - 1)
在最后一种情况下,您正在呼叫 combination2
。如果您更改为 combination
(具有 subList
的合理定义),它会起作用。我想这是中间版本剩下的东西。
案例太多,没必要复杂combinations2
和subList
。
回想一下 combinations 是如何定义的。如果你有一个集合 {a1, ..., aN}
,并且你想从这个集合中 select k
个元素,那么你基本上可以做 两个 事情:
- 您没有将
a1
包含到子集中。那么你必须从剩余的{a2, ..., aN}
. 中得到selectk
个元素
- 您将
a1
包含到子集中。然后你必须从 {a2, ..., aN}
中提取 select k-1
个元素,并将 a0
添加到那些 k-1
个元素中。
这就是公式
C(N, k) = C(N - 1, k) + C(N - 1, k - 1)
来自.
翻译成代码,就是这样:
def comb[A](ls: List[A], k: Int): List[List[A]] = {
if (k == 0) List(Nil)
else ls match {
case Nil => List()
case h :: t => comb(t, k) ++ comb(t, k - 1).map(h :: _)
}
}
示例:
comb(List('a, 'b, 'c, 'd, 'e), 3) foreach println
给出:
List('c, 'd, 'e)
List('b, 'd, 'e)
List('b, 'c, 'e)
List('b, 'c, 'd)
List('a, 'd, 'e)
List('a, 'c, 'e)
List('a, 'c, 'd)
List('a, 'b, 'e)
List('a, 'b, 'd)
List('a, 'b, 'c)
有一种更简单的方法可以做到这一点
def comb[A](n: Int, ls:List[A]): List[List[A]] = {
if(ls.isEmpty) List(Nil)
else ls.toSet[A].subsets.map(_.toList).filter(_.length == n).toList
}
我想在scala中实现一个组合函数,我的代码如下:
def combination[A](n: Int, ls: List[A]): List[List[A]] ={
(n, ls) match{
case (_, Nil) => List(Nil)
case (1, _) => ls.map(List(_))
case (_, _) if n > ls.size => List.empty
case _ => ls.flatMap(x => combination(n - 1, subList(x, ls)).map(x :: _))
}
}
def subList[A](e: A, in: List[A]) = in.takeRight(in.size - in.indexOf(e) - 1)
但结果不是我所期望的。当我打电话给 combination(3, List('a, 'b, 'c, 'd, 'e, 'f)
时。它会给我那些带有一个或两个元素的结果,比如 List('d, 'f), List('f) 等等。谁能帮我找到问题所在?谢谢
更新: 正确的版本是
def combination[A](n: Int, ls: List[A]): List[List[A]] ={
(n, ls) match{
case (_, Nil) => Nil
case (1, _) => ls.map(List(_))
case (_, _) if n > ls.size => Nil
case _ => ls.flatMap(x => combination(n - 1, subList(x, ls)).map(x :: _))
}
}
def subList[A](e: A, in: List[A]) = in.takeRight(in.size - in.indexOf(e) - 1)
在最后一种情况下,您正在呼叫 combination2
。如果您更改为 combination
(具有 subList
的合理定义),它会起作用。我想这是中间版本剩下的东西。
案例太多,没必要复杂combinations2
和subList
。
回想一下 combinations 是如何定义的。如果你有一个集合 {a1, ..., aN}
,并且你想从这个集合中 select k
个元素,那么你基本上可以做 两个 事情:
- 您没有将
a1
包含到子集中。那么你必须从剩余的{a2, ..., aN}
. 中得到select - 您将
a1
包含到子集中。然后你必须从{a2, ..., aN}
中提取 selectk-1
个元素,并将a0
添加到那些k-1
个元素中。
k
个元素
这就是公式
C(N, k) = C(N - 1, k) + C(N - 1, k - 1)
来自.
翻译成代码,就是这样:
def comb[A](ls: List[A], k: Int): List[List[A]] = {
if (k == 0) List(Nil)
else ls match {
case Nil => List()
case h :: t => comb(t, k) ++ comb(t, k - 1).map(h :: _)
}
}
示例:
comb(List('a, 'b, 'c, 'd, 'e), 3) foreach println
给出:
List('c, 'd, 'e)
List('b, 'd, 'e)
List('b, 'c, 'e)
List('b, 'c, 'd)
List('a, 'd, 'e)
List('a, 'c, 'e)
List('a, 'c, 'd)
List('a, 'b, 'e)
List('a, 'b, 'd)
List('a, 'b, 'c)
有一种更简单的方法可以做到这一点
def comb[A](n: Int, ls:List[A]): List[List[A]] = {
if(ls.isEmpty) List(Nil)
else ls.toSet[A].subsets.map(_.toList).filter(_.length == n).toList
}