【发布时间】:2010-05-07 07:30:10
【问题描述】:
在“使用 C# 4.0 的 LINQ To Objects”(Tony Magennis)的第 64 页上,他指出 LINQ 的快速排序排序算法不稳定......
...虽然这可以简单地解决 将结果级联到 ThenBy 或 ThenByDescending 运算符。
嗯?为什么将不稳定的排序级联到另一个排序会修复结果?事实上,我会说这是不可能的。原始订单一旦通过不稳定的排序,就会丢失。我在这里错过了什么?
【问题讨论】:
在“使用 C# 4.0 的 LINQ To Objects”(Tony Magennis)的第 64 页上,他指出 LINQ 的快速排序排序算法不稳定......
...虽然这可以简单地解决 将结果级联到 ThenBy 或 ThenByDescending 运算符。
嗯?为什么将不稳定的排序级联到另一个排序会修复结果?事实上,我会说这是不可能的。原始订单一旦通过不稳定的排序,就会丢失。我在这里错过了什么?
【问题讨论】:
简单地说,他错了。 Linq OrderBy et al. 方法是 documented 执行稳定排序:
此方法执行稳定排序;也就是说,如果两个元素的键相等,则保留元素的顺序。相反,不稳定的排序不会保留具有相同键的元素的顺序。
【讨论】:
不稳定的排序意味着x.OrderBy(...).OrderBy(...) 调用链只能根据最终标准可靠地排序。 x.OrderBy(...).ThenBy(...) 在应用新的排序顺序时显式捕获先前排序顺序的知识。我相信它通过调用IOrderedEnumerable<TElement>.CreateOrderedEnumerable<TKey> 来做到这一点,尽管我不是 100% 确定这一点。
编辑:为了清楚起见,当我说“捕获知识......”时,我并不是说第一个 OrderBy 执行排序,而第二个知道它做了什么。请记住,OrderBy 返回一个IOrderedEnumerable<T>,在有人尝试使用这些元素之前它根本不会执行任何工作。在这种情况下,它永远不会执行排序,因为ThenBy 使用OrderBy 将 如何排序的知识,构建了一个全新的排序器,该排序器以预期的方式和一步。
有人指出 Magennis 在不稳定排序的事情上是错误的。但是,上述描述仍然有效。
【讨论】:
x.OrderBy(a => a.LastName).OrderBy(a => a.FirstName) 而不是x.OrderBy(a => a.LastName).ThenBy(a => a.FirstName)。这比我的回答更有意义:)
他的意思是如果这样做,说orderby LastName,那么任何具有相同姓氏的人都会以不可预知的顺序排序。因此,如果您将其与 orderby LastName, FirstName 结合使用,您可以再次使顺序可预测(当然,姓氏相同的人除外)。
至少,我会这么认为。
【讨论】: