2015-09-07 70 views
5

要訂購Linq的清單,我們必須致電OrderBy首先請撥打ThenBy查詢下屬訂單的結果。訂單清單,頂級訂單未知

我現在處於一種我不知道頂級命令的情況。我有一份應有條件應用的排序清單。

像這樣:

var list = new List<Tuple<int, string, DateTime>>(); 
list.Add(new Tuple<int, string, DateTime>(1, "B", new DateTime(2020, 1, 1))); 
list.Add(new Tuple<int, string, DateTime>(2, "A", new DateTime(2000, 1, 1))); 
list.Add(new Tuple<int, string, DateTime>(3, "C", new DateTime(1900, 1, 1))); 

var orderedList = list; 

if (sortByString) 
{ 
    orderdedList = orderedList.ThenBy(listItem => listItem.Item2); 
} 

if (sortByDateTime) 
{ 
    orderedList = orderedList.ThenBy(listItem => listItem.Item3); 
} 

orderList = orderedList.ThenBy(listItem => listItem.Item1); 

所以名單將始終由項目1的項目2和/或項目3第一排序,並根據條件。

如何在C#中完成此操作?沒有Linq的解決方案也是受歡迎的。

+1

什麼地方錯了,你有什麼 - 只寫'無功orderedList = list.OrderBy(T => t.Item1);'和保留所有內容**但**最後一行 – Carsten

+0

'ThenBy'僅在'IOrderedEnumerable'上可用,因此您可以使用類型檢查。如果'IOrderedEnumerable'使用'ThenBy'否則'OrderBy' – Jehof

+2

@Carsten問題在於Johan想'Item1'排序* last *。這不是很容易閱讀,但這就是他寫的:) – Luaan

回答

7

只需使用

var orderedItems = list.OrderBy(_ => 1); 

這使您的默認(非)排序,並允許你儘可能多的其他添加只需要使用ThenBy即可。

編輯:

正如蒂姆指出,這的確具有特殊的性能損失 - 這似乎是默認的LINQ到對象提供商是不是足夠聰明來重建有序擺脫「非-ordering」。如果你的名單很小,這不是一個問題,但如果它的時間不可忽視,你可能想要做到這一點很難。

例如,你可以使用像

public static IEnumerable<T> AppendOrdering<T, U>(this IEnumerable<T> @this, 
                Func<T, U> selector) 
{ 
    if (@this is IOrderedEnumerable<T>) return @this.ThenBy(selector); 

    return @this.OrderBy(selector); 
} 

一個輔助方法,這不正是你正在做同樣的,但除非你的工作之前已經下令枚舉,它將以同樣的方式工作。

+0

從技術上講,這不是一個無序的,而是一個以相同常數值排序的。因爲每個項目都是相同的,所以使用第一個'ThenBy'等等。可能是微型優化,但在大型集合上它可以有所作爲。爲什麼使用僞比較,如果你可以從右開始?例如:http://csharppad.com/gist/6d19c47c672c81dc2c52(我的電腦上30秒和17秒) –

+0

@TimSchmelter有趣的是,它的差別比我預期的要大得多(當然,在SQL中,這是一個無操作)。在我的電腦上,我得到了16s vs 12s - 如果你需要使用長列表,但仍然非常昂貴,但不像運行時增加100%那麼可怕。但是,也許我只是有一個比你更大的CPU緩存。我肯定會用你的解決方案來代替(當然,在實際上按照OP所要求的方式工作之後:D)。這只是那些奇怪的設計決策之一 - 我理解其中的原因,但它使得查詢組合比需要更難一些。 – Luaan

2

使用IOrderedEnumerable,而不是一個列表和if ... else

IOrderedEnumerable<Tuple<int, string, DateTime>> orderedItems = null; 

if (sortByDateTime) 
    orderedItems = list.OrderBy(listItem => listItem.Item3); 
else if (sortByString) 
    orderedItems = list.OrderBy(listItem => listItem.Item2); 

orderedItems = orderedItems.ThenBy(listItem => listItem.Item1); 
list = orderedItems.ToList(); 
+0

請注意,我的排序條件不是'if else if if {}'if'{if if}}。如果'sortByString'和'sortByDateTime'爲true,那麼第二個orderby會覆蓋第一個。 –

+0

@JohanvanderSlikke:好的,不清楚。編輯我的答案。但是如果'sortByDateTime'有優先級,你應該使用'if(sortByDateTime){}否則如果(sortByString){}' –

-1

你需要使用一個狀態機,如下面的代碼

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     enum State 
     { 
      One, 
      Two, 
     } 
     static void Main(string[] args) 
     { 
      State state = State.A; 

      switch (state) 
      { 
       case State.One: 
        //Order by item one 
        state = State.Two; 
        break; 
       case State.Two: 
        //Order by item two or three 
        state = State.One; 
        break; 
      } 
     } 
    } 
} 


​