c# - 为什么使用 Linq-to-Objects 进行排序会将项目与自身进行比较?

标签 c# algorithm linq sorting base-class-library

考虑以下使用 LINQ OrderByThenBy 的简单代码:

static void Main()
{
  var arr1 = new[] { "Alpha", "Bravo", "Charlie", };

  var coStr = Comparer<string>.Create((x, y) =>
  {
    Console.WriteLine($"Strings: {x} versus {y}");
    return string.CompareOrdinal(x, y);
  });

  arr1.OrderBy(x => x, coStr).ToList();

  Console.WriteLine("--");

  var arr2 = new[]
  {
    new { P = "Alpha", Q = 7, },
    new { P = "Bravo", Q = 9, },
    new { P = "Charlie", Q = 13, },
  };

  var coInt = Comparer<int>.Create((x, y) =>
  {
    Console.WriteLine($"Ints: {x} versus {y}");
    return x.CompareTo(y);
  });

  arr2.OrderBy(x => x.P, coStr).ThenBy(x => x.Q, coInt).ToList();
}

这只是使用一些比较器,将它们比较的内容写到控制台。

在我的硬件和框架版本 (.NET 4.6.2) 上,这是输出:

Strings: Bravo versus Alpha
Strings: Bravo versus Bravo
Strings: Bravo versus Charlie
Strings: Bravo versus Bravo
--
Strings: Bravo versus Alpha
Strings: Bravo versus Bravo
Ints: 9 versus 9
Strings: Bravo versus Charlie
Strings: Bravo versus Bravo
Ints: 9 versus 9

我的问题是:为什么他们会将查询中的项目与自身进行比较?

在第一种情况下,在-- 分隔符之前,他们进行了四次比较。其中两个将条目与自身进行比较(“Strings: Bravo versus Bravo”)。为什么?

在第二种情况下,永远不需要求助于比较 Q 属性(整数);因为在 P 值中没有重复(wrt.ordinal 比较),所以永远不需要从 ThenBy 中打破平局。我们仍然两次看到“整数:9 对 9”。为什么使用具有相同参数的 ThenBy 比较器?

注意:任何比较器在与自身进行比较时都必须返回 0。因此,除非算法只是想检查我们是否正确实现了比较器(无论如何它永远无法完全做到),否则发生了什么?

请注意:在我的示例中,查询生成的元素中没有重复项。

我在另一个示例中看到了同样的问题,查询产生了更多条目。以上我只是举了一个小例子。这也发生在生成偶数 个元素的情况下。

最佳答案

reference sourceOrderBy 使用的 QuickSort 方法中,您可以看到这两行:

while (i < map.Length && CompareKeys(x, map[i]) > 0) i++;
while (j >= 0 && CompareKeys(x, map[j]) < 0) j--;

这些 while 循环会一直运行,直到找到一个不再比 x 指向的元素“更大”(resp.“更小”)的元素。因此,当比较相同 元素时,它们会中断。

我无法从数学上证明它,但我想避免比较相同的元素会使算法更加复杂,并引入开销,这比这种单一比较对性能的影响更大。
(请注意,您的比较器应该实现得足够聪明,以便为相同的元素快速返回 0)

关于c# - 为什么使用 Linq-to-Objects 进行排序会将项目与自身进行比较?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45933348/

相关文章:

c# - 如何修改所有派生类中的方法返回值?

algorithm - 网格中两点之间的最短路径(Matlab)

c# - 将 IEnumerable<int> 中的所有值相乘

c# - 如何分割在 foreach 循环中迭代的元素

c# - 如何使用 C# 运行 Azure Web 作业

c# - Windows 8.1 运行时 (C#) - 将 HttpResponseMessage 内容转换为 BitmapImage

C# 多态性和方法继承

algorithm - 以小于或等于指定的成本找到最快路径

c# - 如何使用 C# 按顺时针方向打印 4x4 数组

javascript - 如何使用 linqjs 链接 "SelectMany"调用(或展平 JSON)