【问题标题】:How does CompareTo method work while Implementing IComparable?在实现 IComparable 时,CompareTo 方法如何工作?
【发布时间】:2015-11-18 16:51:25
【问题描述】:

我有一堂课:

 public class Customer :IComparable<Customer>
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Salary { get; set; }
        }

我也有一个列表:

Customer cust = new Customer() { Id=10,Name="Jack",Salary= 15000};
            Customer cust1 = new Customer() { Id = 10, Name = "Abby", Salary = 5000 };
            Customer cust2 = new Customer() { Id = 10, Name = "Zed", Salary = 152000 };

            List<Customer> CustomerList = new List<Customer>();
            list.Add(cust);
            list.Add(cust1);
            list.Add(cust2);
            CustomerList.Sort();

我明白为什么 list.Sort 对 Customer 不起作用,因为 Customer 类具有三个属性并且它不知道如何对其进行排序。但是,如果我在Customer 类中实现接口IComparable,我就可以按照我想要的任何方式对客户列表进行排序。

public class Customer :IComparable<Customer>
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Salary { get; set; }

            public int CompareTo(Customer other)
            {
                return this.Salary.CompareTo(other.Salary);
            }            
        }

现在我的问题是.. 实现 CompareTo 方法如何让我对CustomerList 进行排序?我什至没有覆盖排序方法或任何东西。 我很困惑,因为我根本没有使用 CompareTo 方法。

我阅读了https://stackoverflow.com/a/4188041/2064292,但它没有回答我的问题。

【问题讨论】:

  • 排序是通过相互比较项目来完成的,看看哪个项目应该放在第一位——如果你已经有一个排序算法(由列表实现提供),它只需要知道如何比较你的项目.这取决于您 - 在实现 CompareTo 时 - 提供确定两个 Customer 对象中的哪一个应该先出现的逻辑。
  • 您是否阅读了 MS 网站上的文档?它有一个完整的示例,说明如何实现接口以及如何使用它。 msdn.microsoft.com/en-us/library/…
  • @Igor 我已经实现了示例中的接口。但我不明白这是如何让CustomerList.Sort(); 工作的?

标签: c# asp.net .net generics interface


【解决方案1】:

当你实现IComparable&lt;T&gt;,创建一个public int CompareTo(T) 方法时,你实际上是在告诉排序机制,它在别处定义,如何通过比较来对你的类的两个实例进行排序一个实例到另一个实例。

就像我说的,实际的排序机制是在别处定义的,例如List&lt;T&gt;.Sort()。无论排序机制使用哪种算法——bubble sortquick sort 等——都无关紧要,但它们都需要一遍又一遍地比较实例以产生排序结果。每次比较两个实例时,都会调用您的 public int CompareTo(T) 方法实现,因为这是您定义如何将您的具体实现相互比较以产生排序结果的地方。

【讨论】:

  • 在Visual Studio中能看到List.Sort的实际排序机制吗?我也猜想 List 的 .Sort 方法在幕后使用了 IComparable 的 CompareTo 方法。我说的对吗?
  • 是的,我在刷新您的帖子之前已经输入了评论。但是在VS中能看到实际的排序机制吗?
  • 关于您的第一个问题,请参见:referencesource.microsoft.com/#mscorlib/system/collections/…
  • 谢谢。这很有帮助。我想知道像我这样的新手应该如何学习所有这些?我的意思是我在 youtube 上随机观看视频,发现当您在课堂上提供 CompareTo 方法的实现时,您可以对 A List 进行排序。如果不是因为那个我可能永远不会发现的视频。
  • @Arbaaz -- 不客气。我作为程序员/软件开发人员的旅程大约在 24 年前开始。不用说,这需要时间和耐心。坚持下去。
【解决方案2】:

虽然有很多不同的排序算法,但它们都归结为同一件事:

四处移动,使“较低”的项目排在“较高”的项目之前。

因此,所有排序都需要能够理解他们正在排序的对象的“较低”和“较高”。

数字很简单;例如3 &lt; 4true,因为 3 低于 4。即使只有数字,我们也必须为intlongdecimaldouble 等编写不同的排序算法,因为我们不能在这里使用泛型(&lt; 等运算符是不能通过泛型获得),当然不能在object 上使用&lt;

因此我们需要定义一些机制,通过该机制 .NET 可以为各种数字以及字符串等提供默认的“较低”和“较高”逻辑。

我们也不能对我们不知道的类型进行任何排序,所以我们再次需要这种机制来知道哪个是“低”,哪个是“高”。

IComaprable&lt;T&gt;IComparable 这样做。

我们还有 IComparer&lt;T&gt;IComparer 允许我们定义自定义订单(例如,对区分大小写和不区分大小写的搜索具有不同的逻辑)或允许某人为不区分大小写的类型提供订单'不实现IComparer

排序通常是这样的:

  1. 如果我们传递了一个IComparer&lt;T&gt; 对象,使用它来决定哪个更低或更高。

  2. 如果我们没有通过IComparer&lt;T&gt;,那么使用Comparer&lt;T&gt;.Default

使用Comparer&lt;T&gt;.Default 意味着当我们没有IComparer&lt;T&gt; 时,我们不需要单独排序,我们只使用默认值。

现在,Comparer&lt;T&gt;.Default 的工作方式如下:

  1. 如果类型实现了IComparable&lt;T&gt;,则调用它。

  2. 否则,如果该类型实现了IComparable(泛型之前的旧接口),则使用它。

  3. 否则抛出异常,因为无法知道如何订购任何东西。

【讨论】:

  • 您的回答很有帮助。我想知道像我这样的新手应该如何知道提供 CompareTo 的实现会让我对 List 进行排序?我的意思是我刚刚发现了这个在 youtube 上随机观看的视频。
  • @Arbaaz 如果您在使用Sort() 方法时遇到问题,首先要查看的是the documentation for the Sort method,它说:“Comparer.Default 属性检查类型 T 是否实现IComparable 泛型接口并使用该实现(如果可用)。如果没有,Comparer.Default 检查类型 T 是否实现 IComparable 接口。如果类型 T 未实现任一接口,Comparer.Default 将引发 InvalidOperationException 。”
【解决方案3】:

CustomerList 是具有泛型类型参数 Customer 的泛型 List。 Sort() 方法的排序算法实现是由 Generic List 提供的,通过查看 Microsoft 文档here,您可以看到实际上根据列表的大小使用了三种算法:

  • 如果分区大小少于 16 个元素,则使用插入 排序算法。
  • 如果分区数超过2 * LogN,其中N 是输入数组的范围,它使用堆排序算法。
  • 否则,它使用快速排序算法。

这些算法都依赖于您对 IComparable 的实现,以便 Customer 类知道如何订购您的客户对象。

【讨论】:

    【解决方案4】:

    在 List.Sort() 的代码中,它将是

    • 将每个对象转换为 IComparable
    • 使用该接口调用 CompareTo(),
    • 该调用的结果决定了排序顺序。

    例如:

    // Sorts a list using IComparable<T>
    public static void Sort(this List<T> list)
    {
       // Worst sorting algorithm ever
       for (int i = 0; i < list.Count; ++i)
       {
          for (int j = 0; j < list.Count; ++j)
          {
              // Assumes that type T implements IComparable<T>
              IComparable<T> first  = (list[i] as IComparable<T>);
              IComparable<T> second = (list[j] as IComparable<T>);
    
              if (first.CompareTo(second) > 0)
              {
                  // wrong order
                  Swap(list, i, j);
              }
          }
       }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多