专栏首页码农阿宇.Net中集合排序还可以这么玩

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • css基础1

    Css(实现了页面和样式的彻底分离) 写入样式表的三种方式: 内联样式表,嵌入样式表,外部样式表。 内联样式表的优先级高于嵌入样式表。嵌入式样式表的优先级大于外...

    码农阿宇
  • windows下安装MongoDB进度条不动

    windows 下安装MongoDB, 在  Installing MongoDB Compass...(this may take a few minutes...

    码农阿宇
  • 基于Win10极简SonarQube C#代码质量分析

    博客有些好些时间未更新了,这几个月的时间里,离开了实习的公司、大学毕了业、来了新公司、转了户口,有点忙,最近总算稍微闲下来了,打算重新拾起博客,坚持写下去。

    码农阿宇
  • 登陆后设置cookie的方法

    阿炬
  • 动态 | ACL 2018 公布四篇最佳 demo 候选论文,三篇论文第一作者来自中国

    雷锋网 AI 科技评论按:7 月 9 日,自然语言处理顶会 ACL 公布了最佳 demo 论文的四篇候选论文,名单如下:

    AI科技评论
  • Mobileye在耶路撒冷启动自动驾驶测试,挑战极限路况

    自动驾驶汽车制造商正在运行更多更真实的测试,英特尔现在也加入战局,将战火蔓延到耶路撒冷。英特尔旗下开发自动驾驶技术的子公司Mobileye,在耶路撒冷启动了测试...

    AiTechYun
  • 数据分析案例:谁是2018当之无愧的“第一”国产电影

    酒香也怕巷子深,虽然票房不是衡量影片好坏的唯一标准,但是票房一定程度反映了包括你我在内的广大群众对该影片的偏好。这里,我们简单粗暴地挑选2018年三部年度总票房...

    TOMOCAT
  • ChIP-seq分析的一般流程方法

    现在ChIP-seq的数据基本是最常见的测序数据类型之一,主要有Transcription factor ChIP-seq和Histone ChIP-seq。前...

    生信编程日常
  • 分享11个表白网源码,不送女朋友!

    雨尘
  • HDU 2037 今年暑假不AC(贪心,区间更新,板子题)

    今年暑假不AC Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (J...

    Angel_Kitty

扫码关注云+社区

领取腾讯云代金券