背景:

学生有名称、学号,

班级有班级名称、班级序号

学校有学校名称、学校编号(序号)

需求

现在需要对学生进行排序

第一排序逻辑

  1. 按学校编号(序号)排列
  2. 再按班级序号排列
  3. 再按学生学号排列

当然,在我们录入数据库信息的时候,有的人可能比较懒,没有录入 学校的序号, 班级的序号,学生的学号 ,怎么办?  那么就Plan B  !

第二排序逻辑

  1. 按学校名称排列
  2. 再按班级的名称排列
  3. 再按学生名称排列

我编写了学校、班级、学生的实体关系代码如下:

namespace Sort
{
public class School
{
public int? Order { get; set; }
public string Name { get; set; }
} public class Class
{
public int? Order { get; set; } public string Name { get; set; } public School School { get; set; }
} public class Student
{
public int? Order { get; set; } public string Name { get; set; } public Class Class { get; set; } }
}

以前写的简单排序,还可以用OrderBy解决,如果之前写过的一篇文章:

《.Net中集合排序还可以这么玩》

但是这里的排序就比较复杂了,用简单的OrderBy恐怕是解决不了了。

Sort

.Net中,对List集合,有一个Sort字方法,让我们选中Sort方法,F12,看看Sort方法长哪样?

可以看到Sort方法一共有四个重载,我们挑最基础的一个,Sort()  0参数的这个,懂了这个,其他几个应该也会懂了,我们看看该方法的描述:

虽然我英语不太好,但是这基础的英语还是能看懂,大致是说:

用默认的比较器对该List进行排序。

那么,这个Comparer(比较器)是什么呢?

IComparable接口

其实,它是接口IComparable下的一个方法,也就是说只有实现了ICoparable接口下的这个叫比较器的方法才能使用Sort进行排序,我们F12进入到IComparable来看看这个接口:

可以看到,该接口只有一个CompareTo方法,我用我蹩脚的英语大致看懂了这句话的意思是:

定义一个比较方法来对制定类型进行排序。

该方法返回类型为Int类型。通过查找查找相关资料,了解到其返回值与其含义如下:

含义

复数

该实例比传入的Other实例小。

0

该实例与传入的Other实例相等。

正数

该实例比传入的Other实例大。

知道了这个原则,我们就可以给Student类继承并实现该方法了。

对文章开头的排序需求,我们重温一下:

第一排序逻辑(Int?)

  1. 按学校编号(序号)排列
  2. 再按班级序号排列
  3. 再按学生学号排列

当序号为空时,用第二种排序逻辑,

第二排序逻辑(String)

    1. 按学校名称排列
    2. 再按班级的名称排列
    3. 再按学生名称排列

其实无非就是对Student中涉及到的Int?和string两种数据类型进行比较。

Int?类型(Nullable)和string已经实现了Compare方法,其中Nullable的如下:

但是为了能更深入地理解该方法的使用,我自己来写一个Int?类型数据比较的方法,如下:

        private int CompareInit(int? x, int? y)
{
if (x == null && y == null) //如果都是空 那么返回0相等
return ; if (x.HasValue && y == null) //如果传入X有值,但是Y是空的,那么X比Y小 返回-1。
return -; if (x == null && y.HasValue) //如果传入X为空,但是Y有值,那么X比Y大 返回1。
return ; if (x.Value > y.Value)
return ; if (x.Value < y.Value)
return -; return ; //否则两个数相等
}

其中,为什么我认为有值的比Null的还小返回-1呢? 因为我想把Null的往后排,把有值的往前排,其他流行的做法是认为有值的是比Null大的,即返回1,大家可以结合自己的业务需求选择。

写好了Int?类型数据比较的方法,还有String类型数据的比较,我就不自己造轮子去写了,用现成的String.CompareOrdinal()方法。

然后,我们开始给Student实现ICompare接口的CompareTo方法,如下:

 public class Student : IComparable<Student>
{
public int? Order { get; set; } public string Name { get; set; } public Class Class { get; set; } public int CompareTo(Student other)
{
if (ReferenceEquals(this, other)) return ; //如果两个值的引用相同,那么直接返回相等。
if (ReferenceEquals(null, other)) return ; //如果该实例是空的,但是传入的实例不是空的,那么返回1 //比较学校的序号
var compareResult = CompareInit(this.Class.School.Order, other.Class.School.Order);
if (compareResult != ) return compareResult; //比较班级的序号
compareResult = CompareInit(this.Class.Order, other.Class.Order);
if (compareResult != ) return compareResult; //比较学生的学号
compareResult = CompareInit(this.Order, other.Order);
if (compareResult != ) return compareResult; //如果以上还未区分出大小,比较学校的名称
compareResult = String.CompareOrdinal(this.Class.School.Name, other.Class.School.Name);
if (compareResult != ) return compareResult; //比较班级的名称
compareResult = String.CompareOrdinal(this.Class.Name, other.Class.Name);
if (compareResult != ) return compareResult; //比较学生的名称
return String.CompareOrdinal(this.Name, other.Name); }

实现该方法后,就可以对List<Student> 使用Sort方法了,我们来试试看。

using System;
using System.Collections.Generic; namespace Sort
{
class Program
{
static void Main(string[] args)
{
var students = InitData(); students.Sort(); //此处执行了Sort方法 Console.WriteLine("Name-Order"); foreach (var student in students)
{
Console.WriteLine($"学校:{student.Class.School.Name}-{student.Class.School.Order}>>班级:{student.Class.Name}-{student.Class.Order}>>学生:{student.Name}-{student.Order}");
} Console.ReadLine();
} static List<Student> InitData() //创建数据
{
var school1 = new School()
{
Order = ,
Name = "A", };
var school2 = new School
{
Name = "B",
Order =
}; var class1 = new Class
{
Order = ,
Name = "",
School = school1,
}; var class2 = new Class
{
Order = ,
Name = "",
School = school1,
}; var class3 = new Class
{
Order = ,
Name = "",
School = school2,
}; var student1 = new Student
{
Order = ,
Name = "",
Class = class1,
}; var student2 = new Student
{
Order = ,
Name = "",
Class = class1,
}; var student3 = new Student
{
Order = ,
Name = "",
Class = class1,
}; var student4 = new Student
{
Order = ,
Name = "",
Class = class2,
}; var student5 = new Student
{
Order = ,
Name = "",
Class = class3,
}; return new List<Student> { student5, student3, student4, student2, student1 }; }
}
}

执行效果如下:

可以看到,学校B虽然是以B开头,但是因为期Order为0比1更靠前,所以以Order为准,学校B排到了最前面。

好几天没写了,写博客对我我而言,意义无非在于加深印象同时把我所掌握的东西分享给大家,这个方法是今天同事教我的,可能对园子里大神来说这比较基础,但是相信如果掌握这个方法,对以后也许中复杂排序会有比较有用,希望对大家也能有所帮助。

项目的GitHub地址:

https://github.com/liuzhenyulive/Sort

如果大家有更好的办法,欢迎下下方留言与我交流。

.Net中集合排序的一种高级玩法的更多相关文章

  1. Word 查找替换高级玩法系列之 -- 把论文中的缩写词快速变成目录下边的注释表

    1. 前言 问题:Word写论文如何把文中的缩写快速转换成注释表? 原来样子: 想要的样子: 2. 步骤 使用查找替换高级用法,替换缩写顺序 选中所有文字 打开查找替换对话框,输入以下表达式: 替换后 ...

  2. 【ASP.NET Core】依赖注入高级玩法——如何注入多个服务实现类

    依赖注入在 ASP.NET Core 中起中很重要的作用,也是一种高大上的编程思想,它的总体原则就是:俺要啥,你就给俺送啥过来.服务类型的实例转由容器自动管理,无需我们在代码中显式处理. 因此,有了依 ...

  3. 【Python基础】random 的高级玩法

    random 模块的高级玩法 1.python 随机产生姓名 方式一: import random xing = [ '赵', '钱', '孙', '李', '周', '吴', '郑', '王', ' ...

  4. maven 高级玩法

    maven 高级玩法 标签(空格分隔): maven 实用技巧 Maven 提速 多线程 # 用 4 个线程构建,以及根据 CPU 核数每个核分配 1 个线程进行构建 $ mvn -T 4 clean ...

  5. 轻量级高性能ORM框架:Dapper高级玩法

    Dapper高级玩法1: 数据库中带下划线的表字段自动匹配无下划线的Model字段. Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; 备 ...

  6. Word 查找替换高级玩法系列之 -- 段首批量添加字符

    打开「查找和替换」输入框,按照下图操作: 更多查找替换高级玩法,参看:Word查找替换高级玩法系列 -- 目录篇 未完 ...... 点击访问原文(进入后根据右侧标签,快速定位到本文)

  7. JAVA中集合输出的四种方式

    在JAVA中Collection输出有四种方式,分别如下: 一) Iterator输出. 该方式适用于Collection的所有子类. public class Hello { public stat ...

  8. 十五天精通WCF——第九天 高级玩法之自定义Behavior

    终于我又看完了二期爱情保卫战,太酸爽了,推荐链接:http://www.iqiyi.com/a_19rrgublqh.html?vfm=2008_aldbd,不多说,谁看谁入迷,下面言归正传, 看看这 ...

  9. [转]十五天精通WCF——第九天 高级玩法之自定义Behavior

    终于我又看完了二期爱情保卫战,太酸爽了,推荐链接:http://www.iqiyi.com/a_19rrgublqh.html?vfm=2008_aldbd,不多说,谁看谁入迷,下面言归正传, 看看这 ...

随机推荐

  1. Linux网络设置(第二版) --互联网寻址过程

    Linux网络设置 --互联网寻址过程 1.TCP/IP与OSI参考模型比较 TCP/IP OSI 物理层 网卡 数据链路层 * MAC地址 网络层 IP,ICMP,ARP协议 传输层 TCP,UDP ...

  2. Google官方网络框架-Volley的使用解析Json以及加载网络图片方法

    Google官方网络框架-Volley的使用解析Json以及加载网络图片方法 Volley是什么? Google I/O 大会上,Google 推出 Volley的一个网络框架 Volley适合什么场 ...

  3. cocos2dx 跨平台编译遇到的几个问题

    首先声明一下自己用的版本 vs2010   cocos2d-x_2.2    ndk_r9 1. 安装cygwin之后,也设置好了 ndk_root, 但是 cd $NDK_ROOT 进入不了, 只好 ...

  4. The table name must be enclosed in double quotation marks or sqare bracket while accessing EXCEL by

      1  Preface DB Query Analyzer is presented by Master Gen feng, Ma from Chinese Mainland. It has Eng ...

  5. java面试笔试题大汇总

    第一,谈谈final, finally, finalize的区别.  最常被问到.   第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以 ...

  6. IdentityServer4实战 - AccessToken 生命周期分析

    一.前言 IdentityServer4实战这个系列主要介绍一些在IdentityServer4(后文称:ids4),在实际使用过程中容易出现的问题,以及使用技巧,不定期更新,谢谢大家关注.使用过id ...

  7. springAOP之代理

    AOP是指面向切面编程. 在学习AOP之前先来了解一下代理,因为传说中的AOP其实也对代理的一种应用. 首先来看这样一段代码: public interface Hello { void say(St ...

  8. laravel 5.5 安装

    PHP要求 PHP> = 7.0.0 OpenSSL PHP扩展 PDO PHP扩展 Mbstring PHP扩展 Tokenizer PHP扩展 XML PHP扩展 通过Composer创建项 ...

  9. JavaScript中push ,pop ,concat ,join方法

    push 方法 将新元素添加到一个数组中,并返回数组的新长度值. arrayObj.push([item1 [item2[. . . [itemN ]]]]) 说明 push 方法将以新元素出现的顺序 ...

  10. Taurus.MVC 支持Asp.Net Core 的过程

    前言: 这些天,似乎.NET Core相关的新闻和文章经常在我眼前晃~~~ 昨天,微软又发布了.Core 2.1,又愰了一下,差点没亮瞎我的眼睛. 好吧,大概是上天给我的暗示,毕竟 CYQ.Data  ...