.Net中的集合排序可以这么玩你知道吗

 更新时间:2018年04月18日 08:15:31   作者:码农阿宇   我要评论

集合为处理大量数据时所用到一种容器类。简单讲就是数据结构算法的具体平台上的实现。下面这篇文章主要给大家介绍了关于.Net中集合排序的一些你可能不知道的用法,文中通过示例代码介绍的非常详细,需要的朋友可以参考下。

C#集合类型概述

集合是.NET FCL(Framework Class Library)中很重要的一部分。所有的集合类都继承自IEnumerable。集合类总体可分为一下几类:关联/非关联型集合,顺序/随机访问集合,顺序/无序集合,泛型/非泛型集合,线程安全集合。

各集合类底层接口关系图

背景:

public class StockQuantity
 {
 public StockQuantity(string status, DateTime dateTime, int quantity)
 {
  Status = status;
  DateTime = dateTime;
  Quantity = quantity;
 }
 public string Status { get; set; }
 public DateTime DateTime { get; set; }
 public int Quantity { get; set; }
}

该对象,主要有三个字段,现在的业务需求是,取到了一个类型为List<StockQuantity>集合StockQuantities,需要对该集合进行三次排序,排序规则及优先级如下:

1.    Status为空的排在后面,不为空的排在前面,不关心Status的内容,只关心Status是否为空。

2.    DateTime升序排序。

3.    Quantity升序排序。

小白我的做法:

我只知道可以对集合用OderBy排序,对以上三条规则,所以设计思路如下。

1.    StockQuantities.OrderBy(u=>u.Status)

错误,

该排序得规则不仅仅会考虑Status是否为空,还会考虑Status的内容。

如果Status是[“b”,”c”,null,”d”] ,那么排序结果是[null,“b”,”c”,”d”]

而我们要的结果是[“b”,”c”,”d” ,null]  (直接把null的丢到最后,别的不动)

怎么办?

暂时不知道,先不管

2.    对DateTime进行升序排序,这简单

StockQuantities.OrderBy(u=>u.DateTime)

半对!

为什么半对,看下面

3.    在排序2的前提下,用OrderBy,也就是StockQuantities.OrderBy(u=>u.DateTime).OrderBy(u=>u.Quantity)

错误!

以上表达式等同于下面两条的表达式:

StockQuantities = StockQuantities.OrderBy(u=>u.DateTime)
StockQuantities = StockQuantities.OrderBy(u=>u.Quantity)

所以第一条代码就是废代码,最终排序还是以Quantity进行排序的。

虽然我是小白,但我还是明白这样是错误的,所以我的做法是

stockQuantities = stockQuantities.OrderBy(u => u.DateTime).ToList();
  foreach (var dateOrder in stockQuantities)
  {
  var datetimeOrderBy = stockQuantities.Where(u => u.DateTime.Date == dateOrder.DateTime.Date) .OrderBy(u => u.Count);
  foreach (var countOrder in datetimeOrderBy)
  {
   if (countOrder.OutPut == false)
   {
   Console.WriteLine($"{countOrder.Status}-{countOrder.DateTime}-{countOrder.Count}");
   countOrder.OutPut = true;
   }
  }
  }
  Console.ReadKey();

采用双层循环,先取到按时间排序的数据 dateOrder,再去和该条数据在同一天的所有数据并对Quantity进行排序,为了防止重复的输出,我同时给StockQuantity对象加上了Output属性,当该属性为false为,则输出该对象的内容,并把Output属性设为true,这样就不会重复输出了,而且实现了先对DateTime排序,再对Quantity进行排序。
So Easy!!

然而,当开心地把这样的代码提交之后,却被同事狠狠地鄙视了,说到:“什么烂代码啊!”然道还有比这更好的代码?

给同事倒了一杯茶,点了一根烟,虚心请教。

大佬做法:

同事给我讲了两招,分别是条件排序、多级排序。

什么是条件排序,怎么用?

1.    StockQuantities.OrderBy(u=>u.Status==null)

这就是条件排序,可是咋一看,给人一种是把Status为空的排前面,不为空的排后面的错觉。

其实不然,我们看到OrderBy里面的一个返回值为bool类型的表达式,该排序先排结果为0(false)的,再排结果为1(true)的。这种排序只考虑返回的bool值,不考虑参数的具体值,所以姑且称它为条件排序。

完全符合排序规则1的要求。

什么是多级排序,怎么用?

2.    利用我上面我的代码排序虽然可以实现先排DateTime,再排Quantity,但是该算法的时间复杂度的n*n,而且给StockQuantity添加了output字段,明显是不科学的。

然而,连续地使用多个OrderBy最终只会生效最后一个OrderBy,天无绝人之路,所以这个时候应该使用ThenBy!!
使用ThenBy可以讲以上的三条排序规则简化如下:

stockQuantities = stockQuantities.OrderBy(u => u.Status==null).ThenBy(u => u.DateTime).ThenBy(u => u.Quantity).ToList();

即可完美地实现再前一个排序前提下进行二级排序。

优化后的完整代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
namespace OrderBy
{
 class Program
 {
 static void Main(string[] args)
 {
  var stockQuantities = new List<StockQuantity>()
  {
  new StockQuantity("正常品",new DateTime(2017,4,16),12 ),
  new StockQuantity("正常品",new DateTime(2017,4,17),15 ),
  new StockQuantity("残次品",new DateTime(2017,4,16),10 ),
  new StockQuantity("残次品",new DateTime(2017,4,17),8 ),
  new StockQuantity(null,new DateTime(2017,4,18),8 ),
  };

  stockQuantities = stockQuantities.OrderBy(u => u.Status==null).ThenBy(u => u.DateTime).ThenBy(u => u.Quantity).ToList();

  foreach (var stockQuantity in stockQuantities)
  {
  Console.WriteLine($"{stockQuantity.Status}-{stockQuantity.DateTime}-{stockQuantity.Quantity}");
  }
  Console.ReadKey();
 }
 }

 public class StockQuantity
 {
 public StockQuantity(string status, DateTime dateTime, int quantity)
 {
  Status = status;
  DateTime = dateTime;
  Quantity = quantity;
 }
 public string Status { get; set; }
 public DateTime DateTime { get; set; }
 public int Quantity { get; set; }
 }
}

简单的一个排序优化,就把程序的时间复杂度从N*N降低到了N,所以在这里把这两种排序技巧分享出来,希望对不会的同学有所帮助。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

相关文章

  • asp.net中使用 Repeater控件拖拽实现排序并同步数据库字段排序

    asp.net中使用 Repeater控件拖拽实现排序并同步数据库字段排序

    这篇文章主要介绍了asp.net中使用 Repeater控件拖拽实现排序并同步数据库字段排序的相关资料,需要的朋友可以参考下
    2015-12-12
  • Asp.Net MVC4通过id更新表单内容的思路详解

    Asp.Net MVC4通过id更新表单内容的思路详解

    一个表单一旦创建完,其中大部分的字段便不可再编辑。只能编辑其中部分字段。下面通过本文给大家分享Asp.Net MVC4通过id更新表单内容的思路详解,需要的朋友参考下吧
    2017-07-07
  • asp.net实现输出xml的方法

    asp.net实现输出xml的方法

    这篇文章主要介绍了asp.net实现输出xml的方法,涉及asp.net针对xml节点的查询、创建、修改、生成等操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • VS Code 1.26 发布 有你想要的新特性?

    VS Code 1.26 发布 有你想要的新特性?

    VS Code 1.26 发布,有你想要的新特性吗?这篇文章主要为大家详细介绍了VS Code 1.26一些主要的更新亮点,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08
  • c# indexof 用法深入理解

    c# indexof 用法深入理解

    在开发过程中经常会使用到c# indexof 查找字串中指定字符或字串首次出现的位置,返首索引值,本文将详细介绍,需要的朋友可以参考下
    2012-11-11
  • 浅谈ASP.NET Core中间件实现分布式 Session

    浅谈ASP.NET Core中间件实现分布式 Session

    这篇文章主要介绍了浅谈ASP.NET Core中间件实现分布式 Session,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • 最详细的ASP.NET微信JS-SDK支付代码

    最详细的ASP.NET微信JS-SDK支付代码

    这篇文章主要为大家介绍了最详细的ASP.NET微信JS-SDK支付代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • asp.net 事件与委托分析

    asp.net 事件与委托分析

    delegate是C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类。与其它的类不同,delegate类能够拥有一个签名(signature),并且它只能持有与它的签名相匹配的方法的引用。
    2009-02-02
  • asp.net+js实现的ajax sugguest搜索提示效果

    asp.net+js实现的ajax sugguest搜索提示效果

    阿会楠根据网上一份原作者不详的代码进行了修改,以适合自己的项目并增加了多个功能。此次放出的代码为基本实现代码,也是最接近原来的代码,略去其他功能。版权归原作者所有。
    2009-04-04
  • .net生成缩略图及水印图片时出现GDI+中发生一般性错误解决方法

    .net生成缩略图及水印图片时出现GDI+中发生一般性错误解决方法

    这篇文章主要介绍了.net生成缩略图及水印图片时出现GDI+中发生一般性错误解决方法 ,需要的朋友可以参考下
    2014-11-11

最新评论