[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+"\t");
17             }
18             list.Sort();
19             Console.WriteLine();
20             Console.WriteLine("排序后....");
21             foreach (int item in list)
22             {
23                 Console.Write(item+"\t");
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方法有三个重载方法。

对自定义类型排序

复制代码
 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 + "\t" + 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 Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\mscorlib.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 + "\t" + 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 + "\t" + p.Age);
26             }
27             Console.Read();
28         }
29     }
30 }
复制代码

总结

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

博客地址: http://www.cnblogs.com/wolf-sun/
博客版权: 本文以学习、研究和分享为主,欢迎转载,但必须在文章页面明显位置给出原文连接。
如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步!
再次感谢您耐心的读完本篇文章。

转载:http://www.cnblogs.com/wolf-sun/p/3574347.html
目录
相关文章
|
2月前
|
存储 C# 索引
C# 一分钟浅谈:数组与集合类的基本操作
【9月更文挑战第1天】本文详细介绍了C#中数组和集合类的基本操作,包括创建、访问、遍历及常见问题的解决方法。数组适用于固定长度的数据存储,而集合类如`List<T>`则提供了动态扩展的能力。文章通过示例代码展示了如何处理索引越界、数组长度不可变及集合容量不足等问题,并提供了解决方案。掌握这些基础知识可使程序更加高效和清晰。
77 2
|
27天前
|
开发框架 NoSQL MongoDB
C#/.NET/.NET Core开发实战教程集合
C#/.NET/.NET Core开发实战教程集合
|
2月前
|
安全 程序员 编译器
C#一分钟浅谈:泛型编程基础
在现代软件开发中,泛型编程是一项关键技能,它使开发者能够编写类型安全且可重用的代码。C# 自 2.0 版本起支持泛型编程,本文将从基础概念入手,逐步深入探讨 C# 中的泛型,并通过具体实例帮助理解常见问题及其解决方法。泛型通过类型参数替代具体类型,提高了代码复用性和类型安全性,减少了运行时性能开销。文章详细介绍了如何定义泛型类和方法,并讨论了常见的易错点及解决方案,帮助读者更好地掌握这一技术。
71 11
|
2月前
|
SQL 开发框架 安全
并发集合与任务并行库:C#中的高效编程实践
在现代软件开发中,多核处理器普及使多线程编程成为提升性能的关键。然而,传统同步模型在高并发下易引发死锁等问题。为此,.NET Framework引入了任务并行库(TPL)和并发集合,简化并发编程并增强代码可维护性。并发集合允许多线程安全访问,如`ConcurrentQueue&lt;T&gt;`和`ConcurrentDictionary&lt;TKey, TValue&gt;`,有效避免数据不一致。TPL则通过`Task`类实现异步操作,提高开发效率。正确使用这些工具可显著提升程序性能,但也需注意任务取消和异常处理等常见问题。
46 1
|
3月前
|
编译器 C#
C#中内置的泛型委托Func与Action
C#中内置的泛型委托Func与Action
62 4
|
3月前
|
存储 C# 索引
C# 集合语法全解
C# 集合语法全解
29 0
|
3月前
|
C#
C# 面向对象编程(三)——接口/枚举类型/泛型
C# 面向对象编程(三)——接口/枚举类型/泛型
31 0
|
5月前
|
存储 C# 开发者
C# 编程基础:注释、变量、常量、数据类型和自定义类型
C# 编程基础:注释、变量、常量、数据类型和自定义类型
|
6月前
|
存储 SQL C#
C# 读取二维数组集合输出到Word预设表格
C# 读取二维数组集合输出到Word预设表格
|
6月前
|
存储 安全 C#
C#使用集合组织相关数据
C#使用集合组织相关数据