天天看點

.Net中集合排序還可以這麼玩

該對象,主要有三個字段,現在的業務需求是,取到了一個類型為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)

錯誤!

以上表達式等同于下面兩條的表達式:

是以第一條代碼就是廢代碼,最終排序還是以Quantity進行排序的。

雖然我是小白,但我還是明白這樣是錯誤的,是以我的做法是

采用雙層循環,先取到按時間排序的資料 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(); 即可完美地實作再前一個排序前提下進行二級排序。

優化後的完整代碼如下:

簡單的一個排序優化,就把程式的時間複雜度從N*N降低到了N,是以在這裡把這兩種排序技巧分享出來,希望對不會的同學有所幫助。