【问题标题】:Default comparer when using OrderBy extension使用 OrderBy 扩展时的默认比较器
【发布时间】:2016-05-02 13:25:01
【问题描述】:

出于好奇:使用以下扩展方法对一堆对象进行排序时使用什么比较器?

OrderBy(x=> x)

背景:我必须检查两个 ISet 实例是否包含相同的元素并考虑使用

bool setsEqual = MySet.SequenceEqual(OtherSet);

方法。由于集合中包含的那些元素的顺序未定义并且可能不同,因此在内部顺序不同的情况下,SequenceEqual 将失败。所以我必须明确定义一个订单。由于订单算法本身是完全不相关的,只要它是稳定的,我只是使用了一个“身份” lambda 表达式:

bool setsEqual = MySet.OrderBy(x => x).SequenceEqual(OtherSet.OrderBy(x => x);

但是“比较对象本身”对代码意味着什么?由于此 OrderBy 扩展方法是通用的,因此必须有一个默认的比较算法,该算法能够在不了解更多对象的情况下对对象进行排序,这意味着必须将排序比较委托给集合的类型元素本身。是否存在元素类型必须支持的接口,或者是否存在默认比较器(可能正在比较对象的内部内存地址)?

【问题讨论】:

  • OrderBy 使用Comparer<TKey>.Default,如您所见here
  • ISet<T> 包含一个 SetEquals 方法,用于测试序列是否相等。
  • 那么,作为对象的直接后代的 TKey 的默认顺序是什么,而不是实现 IComparable?
  • @Udontknow。没有默认顺序 - 默认比较器会抛出异常

标签: c# compare


【解决方案1】:

回答排序问题:排序使用IComparable<T>IComperable(如果未实现)。 IComperable 接口强制您实现 int CompareTo(object) 方法(或 int CompareTo(T) 方法,如果您使用类型化版本)。

元素的顺序由 int 的符号决定。返回值解释如下:

  • 0:这两个对象是等价的(即相同)
  • -1: 比较对象 precedes 这个对象(即在这个对象之前)
  • 1: 比较对象跟随这个对象(即在这个对象之后)

实际值被忽略,符号才是最重要的。如果您实现自己的IComparable 接口,则必须选择排序顺序的语义。

许多对象已经实现了IComparable,就像你所有的数字、字符串等。如果你需要对你自己创建的对象进行排序,你需要明确地实现它。如果您打算将这些对象显示在屏幕上的列表中,这不是一个坏习惯。

至于您的具体情况,您只需要确定一个集合和另一个IEnumerable 是否等效,那么您将使用标准库集合中实现的ISet<T>.SetEquals(IEnumerable<T>) 方法实施。集合,顾名思义,只保证值是唯一的,所以只要元素个数相同,只需要检测一个IEnumerable中的所有元素都可以在集合中找到。

【讨论】:

    【解决方案2】:

    该方法使用IComparable<T>-或IComparable-接口,具体取决于实现了哪一个。如果没有实现,则顺序是任意的。

    但是,您无需在比较集合之前订购实例。只需循环一组并检查其所有元素是否包含在另一组中。或者使用这个:

    var areEqual = firstSet.All(x => secondSet.Contains(x)) && secondSet.All(x => firstSet.Contains(x));
    

    甚至更简单:

    var areEqual = !firstSet.Except(secondSet).Any() && !secondSet.Except(firstSet).Any();
    

    两种方法的执行速度都比您的方法快得多,因为当发现第一个元素不适合时,元素的迭代就会停止。使用 OrderBy 您将循环所有元素,无论是否已经存在不匹配。

    【讨论】:

    • 你不是说var areEqual = !firstSet.Except(secondSet).Any() && !secondSet.Except(firstSet).Any();
    • 对于我的具体情况,Lee已经指出有“SetEquals”方法,但是“否则顺序是任意的”是什么意思? “不确定”意义上的“任意”?相同的输入 -> 可能有不同的结果?
    • 好吧,我猜它不会从一个呼叫更改为另一个呼叫。但是,没有应用排序的属性,您可以将其称为不确定性。例如,如果您不提供此信息,您的程序应如何决定如何对汽车列表进行排序?
    • 至少,所有的汽车都是物体。正如问题中提到的,我可以想到一个默认比较器,它只比较这些对象的指针。另一个想法可能是通过 object.GetHashCode() 进行比较。两种变体都会产生稳定的“确定性”顺序(假设 GetHashCode 已正确实现)。
    • 如果你可以实现GetHashCode——意味着你可以访问这些类并且可以修改它们——你为什么不简单地适当地实现接口。 GetHashCode-方法不是为此目的而设计的。但是我假设如果没有设置比较器,OrderBystatement 将使用任何确定性信息,但你不能说是哪一个。
    【解决方案3】:

    与相等性不同,一般来说,对象没有“默认”比较器。 对于任何类型TKey,似乎Comparer<TKey>.Default 总是返回一个比较器。如果无法确定合理的比较方法,则会出现异常,但仅在使用比较器时才会发生。

    至少一个对象必须实现 IComparable。

    【讨论】:

      猜你喜欢
      • 2012-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多