订单列表,其中顶级订单是未知的

本文关键字:未知 单列表 列表 | 更新日期: 2023-09-27 18:11:28

要用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);

所以列表总是按Item1排序,有条件地先按Item2和/或Item3排序。

如何在c#中实现这一点?也欢迎不使用Linq的解决方案

订单列表,其中顶级订单是未知的

就用

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

这给了你默认的(非)排序,并允许你在使用ThenBy之后添加尽可能多的其他排序。

编辑:

正如Tim所指出的,这确实带来了性能损失——似乎默认的LINQ-to-Objects提供程序不够聪明,无法重建排序以摆脱"非排序"。如果你的列表很小,这不是一个问题,但是如果它占用了不可忽略的时间,你可能想要用困难的方式来做。

例如,您可以使用像 这样的辅助方法
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);
}

这个和你做的不完全一样,但是除非你处理的是一个之前已经排序过的可枚举对象,否则它的工作方式是一样的。

使用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();

您需要使用如下代码所示的状态机

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;
            }
        }
    }
}

​