【问题标题】:Discussing implementation of list flattener function in scala讨论scala中list flattener函数的实现
【发布时间】: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 是不可变的scala List,它必须是线性的(除了最后一部分),因为List 不能被重用。你的也是线性的,你一个一个地添加值(h)。
  • 我不知道为什么它(如果 it 你的意思是 flatten2 实现)必须是线性的。列表确实是不可变的,但我们可以根据需要创建任意数量的列表。我怀疑flatten2 会在foldRight 的每次迭代中重新创建一个新列表,这是累加器和新列表的值的串联。
  • 只需添加一些 pritln 语句,然后在 repl 中运行即可
  • @Moebius,是的,我的意思是flatten2,这也是线性的。正是因为这一行:case Nil => a2,它不必重新创建列表的尾部,它只是重复使用它。

标签: list scala recursion functional-programming


【解决方案1】:

flatten2 (List(List(1,2,3), List(4,5), List(6))) 为例,其扩展为:

append(List(1,2,3),
       append(List(4,5),
              append(List(6),
                     Nil)))

正如a comment in the link 所说,“append 所花费的时间与其第一个参数成正比”,因此“这个函数在所有列表的总长度中是线性的”。 (另一方面,flatten2flatten 都不是尾递归的。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 2020-05-17
    • 2020-07-22
    • 2021-08-05
    • 1970-01-01
    • 2021-08-10
    相关资源
    最近更新 更多