使用比较器进行排序比使用键功能排序要好吗?

时间:2014-08-02 23:06:36

标签: javascript python sorting underscore.js

比较器功能问题

  1. 当函数不可传递,或者它不是反对称时,行为是未定义的。

  2. 预期的返回值,即集合{-1,0,1}中的int,是尴尬的

  3. 它比keyfunc方法更长,并且在声明式样式很好的时候使用命令式样式

  4. 在JavaScript中

    underscore函数_.sortby(myArray, keyFunc) 总是myArray.sort(comparatorFunc)更好吗?

    好吧,如果只有JS中没有这两个问题:

    1. 不幸的是,当你想按照密钥的相反顺序排序时,_.sortBy没有“反向”参数。

    2. _.sortBy不会将数组键视为具有词典排序语义,它只使用原生JS <运算符将它们转换为字符串,因此没有好办法任意词典排序。

    3. 在Python中

      最近实施的mylist.sort(key=keyfunc, reverse=True/False)似乎总是比旧mylist.sort(cmp=comparatorfunc)方法更好。

1 个答案:

答案 0 :(得分:1)

使用比较器 1 的排序比仅使用键选择器的通用灵活更多。然而,这并不意味着一种方法必然是“更好”的。它归结为实现和使用

首先,比较器有一个目的 - 在任意值之间建立排序。 sort函数使用此操作,并且这种排序值的方法必须存在于某个级别。

考虑一个键选择器或仅仅是方便地定义这样的比较器,其中<=>定义了一些自然顺序(注意<=>本身就是比较器!)。因此,键选择器实际上是内置比较器的输入转换

def comparator (a, b): 
    return a.x <=> b.x              -- explicit value selection

def comparatorForKeySelector (keyFn, a, b):
    return keyFn(a) <=> keyFn(b)    -- keys selected by function

如开头所述,选择归结为实施和使用

第一个候选人,underscore.js的排序恰好是一个有限的实现;因为底层比较器不理解如何对返回的数组/序列进行排序,所以不可能在没有诸如字符串重叠之类的黑客的情况下对多个值进行排序。它也无法提供反转排序的能力。这些都是实施问题,可以通过适当修改的内置比较器来解决。

由于元组之间的排序,第二个键选择器候选者Python的键控排序可以轻松地对多个键进行排序。它还允许指定排序方向,使其成为更好的实现。但是,它不允许排序方向在键之间更改(例如,按第二个降序排序第一个键),这也是由于元组之间的排序。

另一个关键选择器候选者,C#的LINQ,由于链接有明确的排序方向,因此没有上述限制:例如。 people.OrderBy(p => p.Height).ThenByDescending(p => p.Weight)。我认为这是理想的&#34;密钥选择器实现,虽然依赖于一些非常漂亮的底层支持。

在查看了三个不同的实现之后,注意到它们可以解决一组具有不同程度成功和灵活性的常见问题,我回过头来看一下:比较器更多通用而不是键选择器,我认为&#34;更好&#34;解决方案是支持[well],以便以最干净的方式解决特定问题。


1 我使用术语比较器来一致地指代一个函数 - 可能是一个运算符 - 它建立了两个值之间的排序。在原始级别,这可能仅使用关系和相等运算符对来实现。


点菜:

  

当函数不可传递,或者它不是反对称时,行为是不确定的。

然后功能被破坏,应该修复。破碎的代码是破坏的代码,不能用作反对使用比较器的参数。

  

预期的返回值,即集合{-1,0,1}中的int,是笨拙的

这是表达这一点的一种非常自然的方式;许多种类接受&#34;小于零&#34;,&#34;零&#34;并且&#34;超过零&#34;值。这些可以更明确地键入 - 例如。使用常量 - 但与此类函数的语义无关。

  

它比keyfunc方法更长,并且在声明式样式很好的时候使用命令式样式

比较器并非隐含的强制性风格&#34;。在功能语言中,它将是一种功能风格&#34;。键选择器通常更简洁明了;但这可以用于大多数专业API。