如果我使用功能范例对序列进行排序,是不是使副本浪费?

时间:2012-05-22 10:14:49

标签: python functional-programming

目标:在不使用内置sorted(..)功能的情况下以功能方式对序列进行排序。

def my_sorted(seq):
    """returns an iterator"""
    pass

动机:在FP方式中,我受到限制:

  • 从不变异seq(可能是迭代器或已实现的列表)
  • 暗示,没有就地排序。

问题1 由于我无法改变seq,我需要维护一个单独的可变数据结构来存储已排序的序列。与就地list.sort()相比,这似乎是浪费。其他函数式编程语言如何处理这个?

问题2 如果我返回一个可变序列,它在功能范例中是否正常?

5 个答案:

答案 0 :(得分:1)

当然排序不能完全是懒惰的(输入的最后一个元素可能是输出中的第一个),但是你可以实现一个计算惰性排序,在读取整个序列之后,只在逐个元素的请求上生成精确排序的输出。您还可以延迟读取输入,直到请求至少一个输出,因此排序和忽略结果将不需要计算。

对于这种计算上懒惰的方法,我所知道的最佳候选者是heapsort算法(你只是预先进行堆构建步骤。)

答案 1 :(得分:1)

就地变异只有在没有其他人引用数据的情况下才是安全的,期望它与排序之前一样。因此,一般而言,为排序结果建立新结构并不是真的浪费。只有以linear方式使用数据时,就地优化才是安全的。

因此,只需分配一个新结构,因为这通常更有用。就地版本是一种特殊情况。

答案 2 :(得分:1)

适当的防御性编程有时会浪费,但你也无能为力。

这就是为什么从一开始就支持功能使用而构建的语言使用结构共享来实现其本机不可变类型;用一种不是为它构建的语言(例如Python)的函数式编程当然不会得到很好的支持。也就是说,排序操作不一定是结构共享的良好候选者(如果需要进行更多的微小更改)。

因此,即使在其他功能语言中,通常 至少有一个复制操作涉及排序。例如,Clojure在一个临时可变数组上委托Java的本机(高度优化)排序操作,并返回一个包装该数组的seq(从而使得结果与用于填充它的输入一样不可移动)。如果输入是不可移动的,并且输出是不可移动的,并且外部世界(特别是任何其他线程)看不到中间发生的事情,则瞬时可变性通常是必要且适当的。

答案 3 :(得分:0)

使用可以创建新数据结构的方式执行的排序算法,例如heapsort或mergesort。

答案 4 :(得分:0)

浪费什么?位?电力?挂钟时间?如果您有足够的cpus和大量数据,并行合并排序可能是最快完成的,但可能产生许多中间表示。

通常,并行化算法可能会导致与串行算法完全不同的优化策略。例如,由于Amdahl定律,在本地重新执行冗余工作以避免共享。这在串行环境中可能被认为是“浪费”,但会导致更加可扩展的算法。