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

背景:

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://www.cnblogs.com/CoderAyu/p/8858447.html

时间: 2024-11-10 09:48:58

.Net中集合排序还可以这么玩的相关文章

.Net中集合排序的一种高级玩法

背景: 学生有名称.学号, 班级有班级名称.班级序号 学校有学校名称.学校编号(序号) 需求 现在需要对学生进行排序 第一排序逻辑 按学校编号(序号)排列 再按班级序号排列 再按学生学号排列 当然,在我们录入数据库信息的时候,有的人可能比较懒,没有录入 学校的序号, 班级的序号,学生的学号 ,怎么办?  那么就Plan B  ! 第二排序逻辑 按学校名称排列 再按班级的名称排列 再按学生名称排列 我编写了学校.班级.学生的实体关系代码如下: namespace Sort { public cla

Java中集合排序的两种方法

import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * * <p> * ClassName CollectionsSort * </p> * <p> * Description 主要介绍两种集合的排序算法<br/> * 第一:java.util.Collections.sort(jav

Java集合中对象排序

集合中的对象排序需求还是比较常见的,当然我们可以重写equals方法,循环比较:同时Java为我们提供了更易使用的APIs.当需要排序的集合或数组不是单纯的数字型时,通常可以使用Comparator或Comparable,以简单的方式实现对象排序或自定义排序. 下面通过两个例子分别用Comparable和Comparator实现对User对象中年龄排序. Comparable接口方式 类自身实现Comparable接口,实现该接口中的compareTo方法. import java.util.A

java中重写Comparator对两个list集合排序

public class test{ public static void main(String[] args) { List<LeaveRequest>  LvRequestList=new List<LeaveRequest>(); List<OtRequest> otRequestList=new List<OtRequest>(); List   allList=new List(); allList.addAll( LvRequestList);

Hadoop学习笔记—11.MapReduce中的排序和分组

一.写在之前的 1.1 回顾Map阶段四大步凑 首先,我们回顾一下在MapReduce中,排序和分组在哪里被执行: 从上图中可以清楚地看出,在Step1.4也就是第四步中,需要对不同分区中的数据进行排序和分组,默认情况下,是按照key进行排序和分组. 1.2 实验场景数据文件 在一些特定的数据文件中,不一定都是类似于WordCount单次统计这种规范的数据,比如下面这类数据,它虽然只有两列,但是却有一定的实践意义. 3 3 3 2 3 1 2 2 2 1 1 1 (1)如果按照第一列升序排列,当

Java集合排序及java集合类详解--(Collection, List, Set, Map)

1         集合框架 1.1         集合框架概述 1.1.1         容器简介 到目前为止,我们已经学习了如何创建多个不同的对象,定义了这些对象以后,我们就可以利用它们来做一些有意义的事情. 举例来说,假设要存储许多雇员,不同的雇员的区别仅在于雇员的身份证号.我们可以通过身份证号来顺序存储每个雇员,但是在内存中实现呢?是不是要准备足够的内存来存储1000个雇员,然后再将这些雇员逐一插入?如果已经插入了500条记录,这时需要插入一个身份证号较低的新雇员,该怎么办呢?是在内

(转)python中集合的运算

原文:http://blog.csdn.net/business122/article/details/7541486 python的set和其他语言类似, 是一个无序不重复元素集, 基本功能包括关系测试和消除重复元素. 集合对象还支持union(联合), intersection(交), difference(差)和sysmmetric difference(对称差集)等数学运算. sets 支持 x in set, len(set),和 for x in set.作为一个无序的集合,sets

Comparable与Comparator,java中的排序与比较

1:比较和排序的概念 比较:两个实体类之间按>,=,<进行比较. 排序:在集合类中,对集合类中的实体进行排序.排序基于的算法基于实体类提供的比较函数. 基本型别都提供了默认的比较算法,如string提供了按字母进行比较,int提供了按整数大小进行比较. 2:Comparable与Comparator but,在软件开发的世界中,任何没有代码的堆概念都是耍流氓.所以,无论我们解释的多么完美,必须show me the code: 我们首先看这样一段代码: public class Collect

java 集合排序

http://www.cnblogs.com/standcloud/articles/2601914.html java 集合排序 Java API针对集合类型排序提供了两种支持:java.util.Collections.sort(java.util.List)java.util.Collections.sort(java.util.List, java.util.Comparator) 第一个方法要求所排序的元素类必须实现java.lang.Comparable接口.第二个方法要求实现一个j