.Net中的集合排序可以這么玩你知道嗎
C#集合類型概述
集合是.NET FCL(Framework Class Library)中很重要的一部分。所有的集合類都繼承自IEnumerable。集合類總體可分為一下幾類:關聯(lián)/非關聯(lián)型集合,順序/隨機訪問集合,順序/無序集合,泛型/非泛型集合,線程安全集合。
各集合類底層接口關系圖
背景:
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; } }
該對象,主要有三個字段,現(xiàn)在的業(yè)務需求是,取到了一個類型為List<StockQuantity>集合StockQuantities,需要對該集合進行三次排序,排序規(guī)則及優(yōu)先級如下:
1. Status為空的排在后面,不為空的排在前面,不關心Status的內容,只關心Status是否為空。
2. DateTime升序排序。
3. Quantity升序排序。
小白我的做法:
我只知道可以對集合用OderBy排序,對以上三條規(guī)則,所以設計思路如下。
1. StockQuantities.OrderBy(u=>u.Status)
錯誤,
該排序得規(guī)則不僅僅會考慮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();
采用雙層循環(huán),先取到按時間排序的數據 dateOrder,再去和該條數據在同一天的所有數據并對Quantity進行排序,為了防止重復的輸出,我同時給StockQuantity對象加上了Output屬性,當該屬性為false為,則輸出該對象的內容,并把Output屬性設為true,這樣就不會重復輸出了,而且實現(xiàn)了先對DateTime排序,再對Quantity進行排序。
So Easy!!
然而,當開心地把這樣的代碼提交之后,卻被同事狠狠地鄙視了,說到:“什么爛代碼啊!”然道還有比這更好的代碼?
給同事倒了一杯茶,點了一根煙,虛心請教。
大佬做法:
同事給我講了兩招,分別是條件排序、多級排序。
什么是條件排序,怎么用?
1. StockQuantities.OrderBy(u=>u.Status==null)
這就是條件排序,可是咋一看,給人一種是把Status為空的排前面,不為空的排后面的錯覺。
其實不然,我們看到OrderBy里面的一個返回值為bool類型的表達式,該排序先排結果為0(false)的,再排結果為1(true)的。這種排序只考慮返回的bool值,不考慮參數的具體值,所以姑且稱它為條件排序。
完全符合排序規(guī)則1的要求。
什么是多級排序,怎么用?
2. 利用我上面我的代碼排序雖然可以實現(xiàn)先排DateTime,再排Quantity,但是該算法的時間復雜度的n*n,而且給StockQuantity添加了output字段,明顯是不科學的。
然而,連續(xù)地使用多個OrderBy最終只會生效最后一個OrderBy,天無絕人之路,所以這個時候應該使用ThenBy??!
使用ThenBy可以講以上的三條排序規(guī)則簡化如下:
stockQuantities = stockQuantities.OrderBy(u => u.Status==null).ThenBy(u => u.DateTime).ThenBy(u => u.Quantity).ToList();
即可完美地實現(xiàn)再前一個排序前提下進行二級排序。
優(yōu)化后的完整代碼如下:
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; } } }
簡單的一個排序優(yōu)化,就把程序的時間復雜度從N*N降低到了N,所以在這里把這兩種排序技巧分享出來,希望對不會的同學有所幫助。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關文章
使用最小?WEB?API?實現(xiàn)文件上傳會遇到的坑
這篇文章主要介紹分享使用最小?WEB?API?實現(xiàn)文件上傳時會遇到的坑,在使用?.NET?6?的最小?WEB?API?來實現(xiàn)相同功能時,總是會意外地遇到了不少坑,下面我們就來看看這些坑都是怎么處理的吧,需要的朋友可以參考下2022-02-02發(fā)布asp.net core時如何修改ASPNETCORE_ENVIRONMENT環(huán)境變量
這篇文章主要介紹了發(fā)布asp.net core時如何修改ASPNETCORE_ENVIRONMENT環(huán)境變量,幫助大家更好的理解和學習使用.net技術,感興趣的朋友可以了解下2021-04-04.NET微服務架構CI/CD自動構建Jenkins+Gitee
這篇文章介紹了.NET使用微服務架構CI/CD自動構建Jenkins+Gitee的方法,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-01-01asp.net異步獲取datatable并顯示的實現(xiàn)方法
這篇文章主要介紹了asp.net異步獲取datatable并顯示的實現(xiàn)方法,結合實例形式分析了asp.net一步操作datatable的相關技巧,需要的朋友可以參考下2016-03-03asp.net頁面觸發(fā)事件panel滾動條高度不變的實現(xiàn)方法
asp.net頁面按鈕點擊觸發(fā)事件后panel滾動條非自動回到頂端,每次都要往下拉一下,關于這個問題的解決方法如下2014-11-11