讨论scala

时间:2016-07-02 14:32:44

标签: list scala recursion functional-programming

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直到函数结束。我是对的吗?

虽然我的实现确实只跨越每个列表一次。我的实施真的更快吗?

1 个答案:

答案 0 :(得分:2)

考虑例如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都不是尾递归的。)