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

转载 2018年04月16日 21:19:31

背景:

复制代码
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,所以在这里把这两种排序技巧分享出来,希望对不会的同学有所帮助。

https://card.weibo.com/article/v3/editor#/history/186963
https://card.weibo.com/article/v3/editor#/history/186608
https://card.weibo.com/article/v3/editor#/history/186424
https://card.weibo.com/article/v3/editor#/history/185801
https://card.weibo.com/article/v3/editor#/history/185781
https://card.weibo.com/article/v3/editor#/history/185463
https://card.weibo.com/article/v3/editor#/history/174288
https://card.weibo.com/article/v3/editor#/history/174119
https://card.weibo.com/article/v3/editor#/history/173561
https://card.weibo.com/article/v3/editor#/history/173336
https://card.weibo.com/article/v3/editor#/history/173082
https://card.weibo.com/article/v3/editor#/history/184630
https://card.weibo.com/article/v3/editor#/history/183057
https://card.weibo.com/article/v3/editor#/history/184940
https://card.weibo.com/article/v3/editor#/history/186882
https://card.weibo.com/article/v3/editor#/history/186884
https://card.weibo.com/article/v3/editor#/history/186966
https://card.weibo.com/article/v3/editor#/history/187201
https://card.weibo.com/article/v3/editor#/history/187391
https://card.weibo.com/article/v3/editor#/history/174940
https://card.weibo.com/article/v3/editor#/history/187695
https://card.weibo.com/article/v3/editor#/history/185492
https://card.weibo.com/article/v3/editor#/history/187410
https://card.weibo.com/article/v3/editor#/history/174972
https://card.weibo.com/article/v3/editor#/history/187714
https://card.weibo.com/article/v3/editor#/history/185531
https://card.weibo.com/article/v3/editor#/history/188021
https://card.weibo.com/article/v3/editor#/history/175465
https://card.weibo.com/article/v3/editor#/history/187712
https://card.weibo.com/article/v3/editor#/history/188523
https://card.weibo.com/article/v3/editor#/history/188120
https://card.weibo.com/article/v3/editor#/history/176032
https://card.weibo.com/article/v3/editor#/history/176073
https://card.weibo.com/article/v3/editor#/history/176022
https://card.weibo.com/article/v3/editor#/history/188239
https://card.weibo.com/article/v3/editor#/history/188643
https://card.weibo.com/article/v3/editor#/history/186373
https://card.weibo.com/article/v3/editor#/history/188251
https://card.weibo.com/article/v3/editor#/history/188665
https://card.weibo.com/article/v3/editor#/history/186385
https://card.weibo.com/article/v3/editor#/history/186508
https://card.weibo.com/article/v3/editor#/history/188788
https://card.weibo.com/article/v3/editor#/history/188382
https://card.weibo.com/article/v3/editor#/history/186627
https://card.weibo.com/article/v3/editor#/history/176292
https://card.weibo.com/article/v3/editor#/history/176523
https://card.weibo.com/article/v3/editor#/history/188817
https://card.weibo.com/article/v3/editor#/history/188818
https://card.weibo.com/article/v3/editor#/history/189232
https://card.weibo.com/article/v3/editor#/history/189237
https://card.weibo.com/article/v3/editor#/history/186919
https://card.weibo.com/article/v3/editor#/history/186921
https://card.weibo.com/article/v3/editor#/history/176408
https://card.weibo.com/article/v3/editor#/history/188683
https://card.weibo.com/article/v3/editor#/history/189175
https://card.weibo.com/article/v3/editor#/history/186813
https://card.weibo.com/article/v3/editor#/history/176522
https://card.weibo.com/article/v3/editor#/history/176562
https://card.weibo.com/article/v3/editor#/history/188886
https://card.weibo.com/article/v3/editor#/history/189283
https://card.weibo.com/article/v3/editor#/history/186984
https://card.weibo.com/article/v3/editor#/history/188906
https://card.weibo.com/article/v3/editor#/history/176578
https://card.weibo.com/article/v3/editor#/history/189299
https://card.weibo.com/article/v3/editor#/history/189300
https://card.weibo.com/article/v3/editor#/history/187004
https://card.weibo.com/article/v3/editor#/history/187005
https://card.weibo.com/article/v3/editor#/history/176613
https://card.weibo.com/article/v3/editor#/history/176614
https://card.weibo.com/article/v3/editor#/history/176687
https://card.weibo.com/article/v3/editor#/history/176692
https://card.weibo.com/article/v3/editor#/history/189480
https://card.weibo.com/article/v3/editor#/history/189482
https://card.weibo.com/article/v3/editor#/history/189063
https://card.weibo.com/article/v3/editor#/history/189067
https://card.weibo.com/article/v3/editor#/history/176713
https://card.weibo.com/article/v3/editor#/history/187171
https://card.weibo.com/article/v3/editor#/history/189622
https://card.weibo.com/article/v3/editor#/history/189624
https://card.weibo.com/article/v3/editor#/history/187236
https://card.weibo.com/article/v3/editor#/history/187237
https://card.weibo.com/article/v3/editor#/history/176714
https://card.weibo.com/article/v3/editor#/history/176820
https://card.weibo.com/article/v3/editor#/history/188223
https://card.weibo.com/article/v3/editor#/history/188226
https://card.weibo.com/article/v3/editor#/history/189694
https://card.weibo.com/article/v3/editor#/history/190006
https://card.weibo.com/article/v3/editor#/history/177134
https://card.weibo.com/article/v3/editor#/history/177135
https://card.weibo.com/article/v3/editor#/history/189554
https://card.weibo.com/article/v3/editor#/history/189556
https://card.weibo.com/article/v3/editor#/history/189637
https://card.weibo.com/article/v3/editor#/history/188465
https://card.weibo.com/article/v3/editor#/history/190067
https://card.weibo.com/article/v3/editor#/history/177250
https://card.weibo.com/article/v3/editor#/history/188810
https://card.weibo.com/article/v3/editor#/history/190213
https://card.weibo.com/article/v3/editor#/history/177397

赢在.NET面试求职

-
  • 1970年01月01日 08:00

.Net中实现常见的排序算法

本文讲述了常见的四种排序算法:冒泡排序,选择排序,插入排序,快速排序并给出了在.net中实现这些算法的代码,(文中程序均默认按升序处理,即数组为从小到大排序)一 冒泡排序[算法描述]给出N个数,用第1...
  • youbl
  • youbl
  • 2006-11-27 23:27:00
  • 1362

ASP.NET Core 和 EF Core 系列教程——排序、筛选、分页和分组

ASP.NET Core 和 EF Core 系列教程——排序、筛选、分页和分组(3 / 10)作者:Tom Dykstra和Rick AndersonContoso 大学示例 web 应用程序演示如...
  • qq_17004327
  • qq_17004327
  • 2017-12-26 21:15:48
  • 617

C#.NET快速排序算法

快速排序,昨天上网找的算法说明,今天用c#给实现的,确实蛮快,嘎嘎简单说明:输入第一个参数是要排序的数组,这里我写的是引用传递,用了ref修饰,其实这里是不是引用传递不是关键,第二个和第三个参数指定要...
  • gaoyunpeng
  • gaoyunpeng
  • 2007-03-01 17:09:00
  • 2946

Java(.NET)经典排序算法之快速排序

转自【http://blog.csdn.net/ouyang_peng】 一、算法思想      快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略...
  • xiaoyiyz
  • xiaoyiyz
  • 2015-12-28 15:58:39
  • 758

.<em>net</em> 字符串<em>排序</em>

.<em>net</em> 字符串<em>排序</em> 2012-10-12 上传大小:961B <em>排序</em>冒泡 用冒泡根据字符串长度<em>排序排序</em> string[] names = new string[4]; names[0] = &quot;adsaa&quot;; names[1] ...
  • 2018年04月18日 00:00

asp.net排序功能

asp.net排序功能
  • happyleo12
  • happyleo12
  • 2016-11-01 15:10:38
  • 59

.NET/C#中对自定义对象集合进行自定义排序的方法

一个集合可否排序,要看系统知不知道排序的规则,像内建的系统类型,int ,string,short,decimal这些,系统知道怎么排序,而如果一个集合里面放置的是自定义类型,比如自己定义了一个Car...
  • liuyuehui110
  • liuyuehui110
  • 2017-04-10 17:03:44
  • 550

Asp.net中,点击GridView表头实现数据的排序

一、实现该功能的基本工作。 1、  先添加一个GridView,取名为gvData。 2、  设置该控件的属性: 操作步骤如下。 设置属性:    ...
  • hxj135812
  • hxj135812
  • 2014-03-10 10:57:54
  • 7407

.NET源码的内部排序实现

使用JetBrains的DotPeek工具可以方便地查看.net的部分源码。于是看了一下.NET的内部是如何实现排序的算法。 在System.Collections.Generic 命名空间下可以看...
  • cuit
  • cuit
  • 2014-06-22 11:42:11
  • 1156
收藏助手
不良信息举报
您举报文章:.Net中集合排序还可以这么玩
举报原因:
原因补充:

(最多只允许输入30个字)