zoukankan      html  css  js  c++  java
  • [c#基础]泛型集合的自定义类型排序

    引用

    最近总有种感觉,自己复习的进度总被项目中的问题给耽搁了,项目中遇到的问题,不总结又不行,只能将复习基础方面的东西放后再放后。一直没研究过太深奥的东西,过去一年一直在基础上打转,写代码,反编译,不停的重复。一直相信,在你不知道要干嘛的时候,浮躁的时候,不如回到最基础的东西上,或许换种思考方式,会有不一样的收获。

    泛型集合List<T>排序

    先看一个简单的例子,int类型的集合:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 namespace Wolfy.SortDemo
     7 {
     8     class Program
     9     {
    10         static void Main(string[] args)
    11         {
    12             List<int> list = new List<int>() {  3, 4, 5, -2, -5, 11, 23,  };
    13             Console.WriteLine("排序前....");
    14             foreach (int item in list)
    15             {
    16                 Console.Write(item+"	");
    17             }
    18             list.Sort();
    19             Console.WriteLine();
    20             Console.WriteLine("排序后....");
    21             foreach (int item in list)
    22             {
    23                 Console.Write(item+"	");
    24             }
    25             Console.Read();
    26         }
    27     }
    28 }

    经sort方法之后,采用了升序的方式进行排列的。

    集合的Sort方法

     1  //
     2         // 摘要: 
     3         //     使用默认比较器对整个 System.Collections.Generic.List<T> 中的元素进行排序。
     4         //
     5         // 异常: 
     6         //   System.InvalidOperationException:
     7         //     默认比较器 System.Collections.Generic.Comparer<T>.Default 找不到 T 类型的 System.IComparable<T>
     8         //     泛型接口或 System.IComparable 接口的实现。
     9         public void Sort();
    10         //
    11         // 摘要: 
    12         //     使用指定的 System.Comparison<T> 对整个 System.Collections.Generic.List<T> 中的元素进行排序。
    13         //
    14         // 参数: 
    15         //   comparison:
    16         //     比较元素时要使用的 System.Comparison<T>。
    17         //
    18         // 异常: 
    19         //   System.ArgumentNullException:
    20         //     comparison 为 null。
    21         //
    22         //   System.ArgumentException:
    23         //     在排序过程中,comparison 的实现会导致错误。 例如,将某个项与其自身进行比较时,comparison 可能不返回 0。
    24         public void Sort(Comparison<T> comparison);
    25         //
    26         // 摘要: 
    27         //     使用指定的比较器对整个 System.Collections.Generic.List<T> 中的元素进行排序。
    28         //
    29         // 参数: 
    30         //   comparer:
    31         //     比较元素时要使用的 System.Collections.Generic.IComparer<T> 实现,或者为 null,表示使用默认比较器 System.Collections.Generic.Comparer<T>.Default。
    32         //
    33         // 异常: 
    34         //   System.InvalidOperationException:
    35         //     comparer 为 null,且默认比较器 System.Collections.Generic.Comparer<T>.Default 找不到
    36         //     T 类型的 System.IComparable<T> 泛型接口或 System.IComparable 接口的实现。
    37         //
    38         //   System.ArgumentException:
    39         //     comparer 的实现导致排序时出现错误。 例如,将某个项与其自身进行比较时,comparer 可能不返回 0。
    40         public void Sort(IComparer<T> comparer);
    41         //
    42         // 摘要: 
    43         //     使用指定的比较器对 System.Collections.Generic.List<T> 中某个范围内的元素进行排序。
    44         //
    45         // 参数: 
    46         //   index:
    47         //     要排序的范围的从零开始的起始索引。
    48         //
    49         //   count:
    50         //     要排序的范围的长度。
    51         //
    52         //   comparer:
    53         //     比较元素时要使用的 System.Collections.Generic.IComparer<T> 实现,或者为 null,表示使用默认比较器 System.Collections.Generic.Comparer<T>.Default。
    54         //
    55         // 异常: 
    56         //   System.ArgumentOutOfRangeException:
    57         //     index 小于 0。 - 或 - count 小于 0。
    58         //
    59         //   System.ArgumentException:
    60         //     index 和 count 未指定 System.Collections.Generic.List<T> 中的有效范围。 - 或 - comparer
    61         //     的实现导致排序时出现错误。 例如,将某个项与其自身进行比较时,comparer 可能不返回 0。
    62         //
    63         //   System.InvalidOperationException:
    64         //     comparer 为 null,且默认比较器 System.Collections.Generic.Comparer<T>.Default 找不到
    65         //     T 类型的 System.IComparable<T> 泛型接口或 System.IComparable 接口的实现。
    66         public void Sort(int index, int count, IComparer<T> comparer);
    Sort()

    可见sort方法有三个重载方法。

    对自定义类型排序

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Wolfy.SortDemo
     8 {
     9     public class Person
    10     {
    11         public string Name { set; get; }
    12         public int Age { set; get; }
    13    }
    14 }

    对Person进行sort后输出,就会出现如下异常:

    对自定义的Person类型进行排序,出现异常。那为什么int类型就没有呢?可以反编译一下,你会发现:

    可见int类型是实现了IComparable这个接口的。那么如果让自定义类型Person也可以排序,那么试试实现该接口。

    修改Person类

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Wolfy.SortDemo
     8 {
     9     public class Person : IComparable
    10     {
    11         public string Name { set; get; }
    12         public int Age { set; get; }
    13 
    14         /// <summary>
    15         /// 实现接口中的方法
    16         /// </summary>
    17         /// <param name="obj"></param>
    18         /// <returns></returns>
    19         public int CompareTo(object obj)
    20         {
    21             Person p = obj as Person;
    22             //因为int32实现了接口IComparable,那么int也有CompareTo方法,直接调用该方法就行
    23             return this.Age.CompareTo(p.Age);
    24         }
    25     }
    26 }

    CompareTo方法的参数为要与之进行比较的另一个同类型对象,返回值为int类型,如果返回值大于0,表示第一个对象大于第二个对象,如果返回值小于0,表示第一个对象小于第二个对象,如果返回0,则两个对象相等。
    定义好默认比较规则后,就可以通过不带参数的Sort方法对集合进行排序。

    测试结果:

    以上采用的sort()方法排序的结果。

     实际使用中,经常需要对集合按照多种不同规则进行排序,这就需要定义其他比较规则,可以在Compare方法中定义,该方法属于IComparer<T>泛型接口,请看下面的代码:

     1 namespace Wolfy.SortDemo
     2 {
     3     public class PersonNameDesc:IComparer<Person>
     4     {
     5         //存放排序器实例
     6         public static PersonNameDesc NameDesc = new PersonNameDesc();
     7         public int Compare(Person x, Person y)
     8         {
     9             return System.Collections.Comparer.Default.Compare(x.Name, y.Name);
    10         }
    11     }
    12 }

    Compare方法的参数为要进行比较的两个同类型对象,返回值为int类型,返回值处理规则与CompareTo方法相同。其中的Comparer.Default返回一个内置的Comparer对象,用于比较两个同类型对象。

        下面用新定义的这个比较器对集合进行排序:

     1  class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             List<Person> list = new List<Person>()
     6             {
     7                 new Person(){Name="a",Age=2},
     8                 new Person(){Name="d",Age=9},
     9                 new Person(){Name="b",Age=3},
    10                 new Person(){Name="c",Age=10}
    11             };
    12        
    13             list.Sort(PersonNameDesc.NameDesc);
    14             foreach (Person p in list)
    15             {
    16                 Console.WriteLine(p.Name + "	" + p.Age);
    17             }
    18             Console.Read();
    19         }
    20     }

    测试结果:

     Sort(int index, int count, IComparer<T> comparer)

    同上面的类似,只是这个是取范围的。

    Sort(Comparison<T> comparison)

    sort方法的一个重载是Comparison<T>类型的参数,那么Comparison到底是什么东东呢?,说实话,不F12还真发现不了。

     1 #region 程序集 mscorlib.dll, v4.0.0.0
     2 // C:Program FilesReference AssembliesMicrosoftFramework.NETFrameworkv4.5mscorlib.dll
     3 #endregion
     4 
     5 namespace System
     6 {
     7     // 摘要: 
     8     //     表示比较同一类型的两个对象的方法。
     9     //
    10     // 参数: 
    11     //   x:
    12     //     要比较的第一个对象。
    13     //
    14     //   y:
    15     //     要比较的第二个对象。
    16     //
    17     // 类型参数: 
    18     //   T:
    19     //     要比较的对象的类型。
    20     //
    21     // 返回结果: 
    22     //     一个有符号整数,指示 x 与 y 的相对值,如下表所示。 值 含义 小于 0 x 小于 y。 0 x 等于 y。 大于 0 x 大于 y。
    23     public delegate int Comparison<in T>(T x, T y);
    24 }

    看到这里就该笑了,委托啊,那么岂不是可以匿名委托,岂不是更方便啊。那么排序可以这样了。

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 namespace Wolfy.SortDemo
     7 {
     8     class Program
     9     {
    10         static void Main(string[] args)
    11         {
    12             List<Person> list = new List<Person>()
    13             {
    14                 new Person(){Name="a",Age=2},
    15                 new Person(){Name="b",Age=9},
    16                 new Person(){Name="c",Age=3},
    17                 new Person(){Name="d",Age=10}
    18             };
    19             //匿名委托
    20             list.Sort((a,b)=>a.Age-b.Age);
    21             foreach (Person p in list)
    22             {
    23                 Console.WriteLine(p.Name + "	" + p.Age);
    24             }
    25             Console.Read();
    26         }
    27     }
    28 }

    结果:

    使用Linq排序

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 namespace Wolfy.SortDemo
     7 {
     8     class Program
     9     {
    10         static void Main(string[] args)
    11         {
    12             List<Person> list = new List<Person>()
    13             {
    14                 new Person(){Name="a",Age=2},
    15                 new Person(){Name="d",Age=9},
    16                 new Person(){Name="b",Age=3},
    17                 new Person(){Name="c",Age=10}
    18             };
    19             var l = from p in list
    20                     orderby p.Age descending
    21                     select p;
    22             //list.Sort(PersonNameDesc.NameDesc);
    23             foreach (Person p in l)
    24             {
    25                 Console.WriteLine(p.Name + "	" + p.Age);
    26             }
    27             Console.Read();
    28         }
    29     }
    30 }

    总结

     从下班弄到现在,一直整理笔记。泛型集合的排序选一个顺手的就行。 

  • 相关阅读:
    springMVC+freemarker中Could not resolve view with name... 问题解决
    mybatis中if test 语句 当参数类型为string时,如何写判断条件
    博科交换机升级FOS系统
    response.redirect 和Server.Transfer 的区别
    win7 安装MyGeneration版本,没有安装mdac的解决办法
    Zen Cart的sidebox机制
    ASPCMS相册 实现每张图片对应一段文字
    ZEN CART 系统想在首页调用 新闻插件 的 新闻列表的方法
    JS获得来源页
    zen cart去掉zenid的简单方法
  • 原文地址:https://www.cnblogs.com/wolf-sun/p/3574347.html
Copyright © 2011-2022 走看看