2015-09-07 110 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; 
      } 
     } 
    } 
} 


​