【发布时间】:2016-11-04 19:13:08
【问题描述】:
flatten 函数是一个函数,它接受一个列表并返回一个列表,该列表是所有列表的连接。作为functional programming in scala 的练习,我们必须以线性复杂度实现该功能。我的解决方案是:
def flatten[A](l: List[List[A]]): List[A] = {
def outer(ll: List[List[A]]):List[A] = {
ll match {
case Nil => Nil
case Cons(h,t) => inner(t, h)
}
}
def inner(atEnd: List[List[A]], ll: List[A]): List[A] = {
ll match {
case Nil => outer(atEnd)
case Cons(h,t) => Cons(h, inner(atEnd, t))
}
}
outer(l)
}
它有效。现在我看了solution proposed:
def append[A](a1: List[A], a2: List[A]): List[A] =
a1 match {
case Nil => a2
case Cons(h,t) => Cons(h, append(t, a2))
}
def flatten2[A](l: List[List[A]]): List[A] =
foldRight(l, Nil:List[A])(append)
我怀疑flatten2 真的是线性的。在foldLeft 的每次迭代中,都会调用函数append。该函数将解析累加器的所有节点。第一次,累加器是Nil,第二次是l.get(1),然后是l.get(1) + l.get(2)...所以l中的第一个列表不会只被越过一次,而是l.length - 1直到结束功能。我说的对吗?
虽然我的实现实际上只跨越了每个列表一次。我的实现真的更快吗?
【问题讨论】:
-
如果这个
List是不可变的scalaList,它必须是线性的(除了最后一部分),因为List不能被重用。你的也是线性的,你一个一个地添加值(h)。 -
我不知道为什么它(如果
it你的意思是flatten2实现)必须是线性的。列表确实是不可变的,但我们可以根据需要创建任意数量的列表。我怀疑flatten2会在foldRight的每次迭代中重新创建一个新列表,这是累加器和新列表的值的串联。 -
只需添加一些 pritln 语句,然后在 repl 中运行即可
-
@Moebius,是的,我的意思是
flatten2,这也是线性的。正是因为这一行:case Nil => a2,它不必重新创建列表的尾部,它只是重复使用它。
标签: list scala recursion functional-programming