【问题标题】:How do I use the IComparable interface?如何使用 IComparable 接口?
【发布时间】:2017-02-10 13:32:39
【问题描述】:

我需要一个关于如何使用IComparable 接口的基本示例,以便我可以按升序或降序以及我正在排序的对象类型的不同字段进行排序。

【问题讨论】:

    标签: c# .net icomparable


    【解决方案1】:

    好吧,既然您使用的是List<T>,那么只使用Comparison<T> 会简单得多,例如:

    List<Foo> data = ...
    // sort by name descending
    data.Sort((x,y) => -x.Name.CompareTo(y.Name));
    

    当然,你可以使用 LINQ:

    var ordered = data.OrderByDescending(x=>x.Name);
    

    但是您可以很容易地在List&lt;T&gt; 中重新引入它(用于就地重新订购);下面是一个示例,它允许 SortList&lt;T&gt; 上使用 lambda 语法:

    using System;
    using System.Collections.Generic;  
    
    class Foo { // formatted for vertical space
        public string Bar{get;set;}
    }
    static class Program {
        static void Main() {
            List<Foo> data = new List<Foo> {
                new Foo {Bar = "abc"}, new Foo {Bar = "jkl"},
                new Foo {Bar = "def"}, new Foo {Bar = "ghi"}
            };
            data.SortDescending(x => x.Bar);
            foreach (var row in data) {
                Console.WriteLine(row.Bar);
            }
        }
    
        static void Sort<TSource, TValue>(this List<TSource> source,
                Func<TSource, TValue> selector) {
            var comparer = Comparer<TValue>.Default;
            source.Sort((x,y)=>comparer.Compare(selector(x),selector(y)));
        }
        static void SortDescending<TSource, TValue>(this List<TSource> source,
                Func<TSource, TValue> selector) {
            var comparer = Comparer<TValue>.Default;
            source.Sort((x,y)=>comparer.Compare(selector(y),selector(x)));
        }
    }
    

    【讨论】:

    • 您的答案开始有点混乱,它假定我已经阅读了不在问题中但在 OP 发布的答案中的信息。
    【解决方案2】:

    这是一个简单的例子:

    public class SortableItem : IComparable<SortableItem>
    {
        public int someNumber;
    
        #region IComparable<SortableItem> Members
    
        public int CompareTo(SortableItem other)
        {
            int ret = -1;
            if (someNumber < other.someNumber)
                ret = -1;
            else if (someNumber > other.someNumber)
                ret = 1;
            else if (someNumber == other.someNumber)
                ret = 0;
            return ret;
        }
    
        #endregion
    }
    

    “这很好,但是如果我想能够控制排序顺序,或者按另一个字段排序呢?”

    简单。我们需要做的就是向对象添加更多字段。首先,我们将为不同的排序类型添加一个字符串,然后我们将添加一个布尔值来表示我们是按降序还是升序排序,然后添加一个字段来确定我们要搜索的字段。

    public class SortableItem : IComparable<SortableItem>
    {
        public enum SortFieldType { SortNumber, SortString }
    
        public int someNumber = -1;
        public string someString = "";
        public bool descending = true;    
        public SortFieldType sortField = SortableItem.SortFieldType.SortNumber;        
    
        #region IComparable<SortableItem> Members
    
        public int CompareTo(SortableItem other)
        {
            int ret = -1;
            if(sortField == SortableItem.SortFieldType.SortString)
            {
                // A lot of other objects implement IComparable as well.
                // Take advantage of this.
                ret = someString.CompareTo(other.someString);
            }
            else
            {
                if (someNumber < other.someNumber)
                    ret = -1;
                else if (someNumber > other.someNumber)
                    ret = 1;
                else if (someNumber == other.someNumber)
                    ret = 0;
            }
            // A quick way to switch sort order:
            // -1 becomes 1, 1 becomes -1, 0 stays the same.
            if(!descending) ret = ret * -1; 
    
            return ret;
        }
    
        #endregion
    
        public override string ToString()
        {
           if(sortField == SortableItem.SortFieldType.SortString)
              return someString;
           else
              return someNumber.ToString();
        }
    }
    

    “告诉我怎么做!”

    既然你问得这么好。

    static class Program
    {
        static void Main()
        {
    
            List<SortableItem> items = new List<SortableItem>();
            SortableItem temp = new SortableItem();
            temp.someString = "Hello";
            temp.someNumber = 1;
            items.Add(temp);
            temp = new SortableItem();
            temp.someString = "World";
            temp.someNumber = 2;
            items.Add(temp);
            SortByString(items);
            Output(items);
            SortAscending(items);
            Output(items);
            SortByNumber(items);
            Output(items);
            SortDescending(items);
            Output(items);
            Console.ReadKey();
        }
    
        public static void SortDescending(List<SortableItem> items)
        {
            foreach (SortableItem item in items)
                item.descending = true;
        }
        public static void SortAscending(List<SortableItem> items)
        {
            foreach (SortableItem item in items)
                item.descending = false;
        }
        public static void SortByNumber(List<SortableItem> items)
        {
            foreach (SortableItem item in items)
                item.sortField = SortableItem.SortFieldType.SortNumber;
        }
        public static void SortByString(List<SortableItem> items)
        {
            foreach (SortableItem item in items)
                item.sortField = SortableItem.SortFieldType.SortString;
        }
        public static void Output(List<SortableItem> items)
        {
            items.Sort();
            for (int i = 0; i < items.Count; i++)
                Console.WriteLine("Item " + i + ": " + items[i].ToString());
        }
    }
    

    【讨论】:

    • 这实际上很糟糕,很抱歉。有更好的方法,尤其是使用 LINQ 或受 LINQ 启发的方法...
    • 如果您有更好的想法,也没有什么不能回答这个问题的。
    • 我有 - 我只是在写它;-p
    【解决方案3】:

    如果你想要动态排序,你可以使用 LINQ

    var itemsOrderedByNumber = ( from item in GetClasses() orderby item.Number select item ).ToList();
    var itemsOrderedByText = ( from item in GetClasses() orderby item.Text select item ).ToList();
    var itemsOrderedByDate = ( from item in GetClasses() orderby item.Date select item ).ToList();
    

    或List类的“排序”方法:

    List<Class1> itemsOrderedByNumber2 = new List<Class1>( GetClasses() );
    itemsOrderedByNumber2.Sort( ( a, b ) => Comparer<int>.Default.Compare( a.Number, b.Number ) );
    
    List<Class1> itemsOrderedByText2 = new List<Class1>( GetClasses() );
    itemsOrderedByText2.Sort( ( a, b ) => Comparer<string>.Default.Compare( a.Text, b.Text ) );
    
    List<Class1> itemsOrderedByDate2 = new List<Class1>( GetClasses() );
    itemsOrderedByDate2.Sort( ( a, b ) => Comparer<DateTime>.Default.Compare( a.Date, b.Date ) );
    

    【讨论】:

      【解决方案4】:

      你可以用它来排序列表

      namespace GenaricClass
      {
          class Employee :IComparable<Employee>
          {
              public string Name { get; set; }
              public double Salary { get; set; }
      
              public int CompareTo(Employee other)
              {
                  if (this.Salary < other.Salary) return 1;
                  else if (this.Salary > other.Salary) return -1;
                  else return 0;
              }
      
              public static void Main()
              {
                  List<Employee> empList = new List<Employee>()
                  {
                      new Employee{Name="a",Salary=140000},
                      new Employee{Name="b",Salary=120000},
                      new Employee{Name="c",Salary=160000},
                      new Employee{Name="d",Salary=10000}
                  };
                  empList.Sort();
                  foreach (Employee emp in empList)
                  {
                      System.Console.Write(emp.Salary +",");
                  }
                  System.Console.ReadKey();
              }
          }
      }
      

      【讨论】:

        【解决方案5】:

        这可能与排序顺序无关,但我认为它仍然是 IComparable 的一个有趣用法:

        public static void MustBeInRange<T>(this T x, T minimum, T maximum, string paramName)
        where T : IComparable<T>
        {
            bool underMinimum = (x.CompareTo(minimum) < 0);
            bool overMaximum = (x.CompareTo(maximum) > 0);
            if (underMinimum || overMaximum)
            {
                string message = string.Format(
                    System.Globalization.CultureInfo.InvariantCulture,
                    "Value outside of [{0},{1}] not allowed/expected",
                    minimum, maximum
                );
                if (string.IsNullOrEmpty(paramName))
                {
                    Exception noInner = null;
                    throw new ArgumentOutOfRangeException(message, noInner);
                }
                else
                {
                    throw new ArgumentOutOfRangeException(paramName, x, message);
                }
            }
        }
        
        public static void MustBeInRange<T>(this T x, T minimum, T maximum)
        where T : IComparable<T> { x.MustBeInRange(minimum, maximum, null); }
        

        这些简单的扩展方法允许您对任何实现IComparable 的类型进行参数范围检查,如下所示:

        public void SomeMethod(int percentage, string file) {
            percentage.MustBeInRange(0, 100, "percentage");
            file.MustBeInRange("file000", "file999", "file");
            // do something with percentage and file
            // (caller will have gotten ArgumentOutOfRangeExceptions when applicable)
        }
        

        【讨论】:

        • 说实话,你不太可能在不是IComparable&lt;T&gt;IComparable 的类型上使用它,所以我会放弃约束并使用Comparer.Default。例如,这是 LINQ-to-Objects 如何做 Min/Max。
        • 没想到。谢谢你的提示。但是,这不会显示扩展方法的所有内容(= 在类型上我“不太可能使用它”),而使用类型约束它只会显示在实际上是 IComparable 的类型上?
        【解决方案6】:
        using System;
        using System.Collections.Generic;
        using System.Text;
        
        namespace Sorting_ComplexTypes
        {
            class Program
            {
                static void Main(string[] args)
                {
                    Customer customer1 = new Customer {
                        ID = 101,
                        Name = "Mark",
                        Salary = 2400,
                        Type = "Retail Customers"
                    };
                    Customer customer2 = new Customer
                    {
                        ID = 102,
                        Name = "Brian",
                        Salary = 5000,
                        Type = "Retail Customers"
                    };
                    Customer customer3 = new Customer
                    {
                        ID = 103,
                        Name = "Steve",
                        Salary = 3400,
                        Type = "Retail Customers"
                    };
        
                    List<Customer> customer = new List<Customer>();
                    customer.Add(customer1);
                    customer.Add(customer2);
                    customer.Add(customer3);
        
                    Console.WriteLine("Before Sorting");
                    foreach(Customer c in customer)
                    {
                        Console.WriteLine(c.Name);
                    }
        
                    customer.Sort();
                    Console.WriteLine("After Sorting");
                    foreach(Customer c in customer)
                    {
                        Console.WriteLine(c.Name);
                    }
        
                    customer.Reverse();
                    Console.WriteLine("Reverse Sorting");
                    foreach (Customer c in customer)
                    {
                        Console.WriteLine(c.Name);
                    }
                    }
                }
            }
            public class Customer : IComparable<Customer>
            {
                public int ID { get; set; }
                public string Name { get; set; }
                public int Salary { get; set; }
                public string Type { get; set; }
        
                public int CompareTo(Customer other)
                {
                    return this.Name.CompareTo(other.Name);
                }
            }
        

        【讨论】:

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