我正在尝试scala-99 P09。
作者给出的答案是:
object P09 {
def pack[A](ls: List[A]): List[List[A]] = {
if (ls.isEmpty) List(List())
else {
val (packed, next) = ls span { _ == ls.head }
if (next == Nil) List(packed)
else packed :: pack(next)
}
}
}
它给出了:
pack(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))
// res0: List[List[Symbol]] = List(List('a, 'a, 'a, 'a), List('b), List('c, 'c), List('a, 'a), List('d), List('e, 'e, 'e, 'e))
和
pack(List[Int]()) // => res1: List[List[Int]] = List(List())
但是,我认为它应该是List[List[Int]] = List()
出于什么原因,作者返回List(List())
而不是List()
?
今天,我遇到了P26(生成从列表的N个元素中选择的K个不同对象的组合。),我首先给出了以下解决方案:
def combinationsOf[A](n: Int, ls: List[A]): List[List[A]] = {
if (n < 0 || n > ls.length) throw new IllegalArgumentException
else if (n == 0) List.empty[List[A]]
else if (n == ls.length) List(ls)
else combinationsOf(n - 1, ls.tail).map(ls.head :: _) ::: combinationsOf(n, ls.tail)
}
但是当给定K = 3和List(1,2,3,4)时,它只输出(1,2,4), (1,3,4), (2,3,4)
,这是错误的。我知道我的代码有什么问题。所以我做对了:
def combinationsOf[A](n: Int, ls: List[A]): List[List[A]] = {
if (n < 0 || n > ls.length) throw new IllegalArgumentException
else if (n == 0) List(Nil)
else if (n == ls.length) List(ls)
else combinationsOf(n - 1, ls.tail).map(ls.head :: _) ::: combinationsOf(n, ls.tail)
}
我无法理解的东西仍然存在。当List()似乎更合适时,为什么需要List(Nil)
?
答案 0 :(得分:1)
我不知道。我还认为如果输入列表为空,它应该返回一个空列表。 我会这样写的
def pack[A](ls: List[A]): List[List[A]] = {
if (ls.isEmpty) List.empty[List[A]]
else {
val (packed, next) = ls span { _ == ls.head }
packed :: pack(next)
}
}
甚至更短
def pack[A](ls: List[A]): List[List[A]] = ls.groupBy(identity).values.toList
答案 1 :(得分:1)
来自Ninety-Nine Scala Problems页面:
这些改编自Werner Hett在瑞士伯尔尼伯尔尼应用科学大学撰写的Ninety-Nine Prolog Problems。我(Phil Gold)已经改变了它们以便更适合在Scala中编程。我们非常感谢您的反馈意见,尤其是标记为TODO的任何内容。
现在,如果你检查Ninety-Nine Prolog Problems,你会发现问题1.09基本上是这里列出的问题。 Prolog Problems网站还提供解决方案,如果您选中the solution for 1.09,您会看到:
pack([],[]).
我不是一个prolog程序员,但我很确定这意味着作为输入的空列表会导致一个空列表作为输出。如果输入是空列表,则此问题的99 Lisp Problems和99 Haskel Problems解决方案也会提供空列表(不是包含单个空列表的列表)。
我认为答案中的List(List())
表达看起来好像是因为混淆了如何创建一个空的列表列表。正如@SpiderPig在他修改的解决方案中所示,返回List()
而不是List(List())
实际上对简化递归逻辑做了很多工作。
99 Scala Problems页面有一个提供反馈的链接,因此您可以随时指出此问题并建议修复。
我无法理解的东西仍然存在。当List()似乎更合适时,为什么需要List(Nil)?
在函数的最后一种情况下,map
覆盖所有递归调用的结果。如果您的递归调用返回List()
,那么您将映射一个空列表,该列表将始终返回一个空列表。相反,如果map(ls.head :: _)
为List(ls.head)
而不是_
,List(Nil)
将返回List()
。您可以通过为 n = 1 :
def combinationsOf[A](n: Int, ls: List[A]): List[List[A]] = {
require(0 <= n && n <= ls.length) // using require is probably better style
if (n == 0) List()
else if (n == 1) ls.map(List(_)) // fixes map over empty list problem
else if (n == ls.length) List(ls)
else combinationsOf(n - 1, ls.tail).map(ls.head :: _) ::: combinationsOf(n, ls.tail)
}
另请注意,我没有明确抛出IllegalArgumentException
,而是将第一个案例与require
交换(如果该子句为假,则会抛出IllegalArgumentException
。