c# linq 相当复杂的排序

标签 c# linq sorting

我有一个对象列表,我需要整理成一个相当复杂的排序顺序。

我是 linq 和 c#/.net 的新手(但不是其他语言编程的新手),所以我希望能得到一些提示,告诉我我需要走什么方向。

我的列表(简化版)如下所示:

List[
    {nr:  1, originatesFrom: null, lastChanged: DateTime(2018,5,3)},
    {nr:  2, originatesFrom: null, lastChanged: DateTime(2018,5,3)},
    {nr:  3, originatesFrom: null, lastChanged: DateTime(2018,5,3)},
    {nr:  4, originatesFrom: 1,    lastChanged: DateTime(2018,5,1)},
    {nr:  5, originatesFrom: 2,    lastChanged: DateTime(2018,5,1)},
    {nr:  6, originatesFrom: 1,    lastChanged: DateTime(2018,5,7)},
    {nr:  7, originatesFrom: 1,    lastChanged: DateTime(2018,5,4)},
    {nr:  8, originatesFrom: 3,    lastChanged: DateTime(2018,5,13)},
    {nr:  9, originatesFrom: 1,    lastChanged: DateTime(2018,5,13)},
    {nr: 10, originatesFrom: 3,    lastChanged: DateTime(2018,5,10)},
    {nr: 11, originatesFrom: 3,    lastChanged: DateTime(2018,5,18)}
]

我需要把它按摩成这样:

List[
    {nr:  5, originatesFrom: 2,    lastChanged: DateTime(2018,5,1)},
    {nr:  2, originatesFrom: null, lastChanged: DateTime(2018,5,3)},
    {nr:  9, originatesFrom: 1,    lastChanged: DateTime(2018,5,13)},
    {nr:  6, originatesFrom: 1     lastChanged: DateTime(2018,5,7)},
    {nr:  7, originatesFrom: 1,    lastChanged: DateTime(2018,5,4)},
    {nr:  4, originatesFrom: 1,    lastChanged: DateTime(2018,5,1)},
    {nr:  1, originatesFrom: null, lastChanged: DateTime(2018,5,3)},
    {nr: 11, originatesFrom: 3,    lastChanged: DateTime(2018,5,18)},
    {nr:  8, originatesFrom: 3,    lastChanged: DateTime(2018,5,13)},
    {nr: 10, originatesFrom: 3,    lastChanged: DateTime(2018,5,10)},
    {nr:  3, originatesFrom: null, lastChanged: DateTime(2018,5,3)}
]

复杂的排序规则如下:按 originatesFrom 分组,在每个组内按 lastChanged 降序排序,组按(第一个实例的)lastChanged 升序排序。最后,originatesFrom 中为 null 的那些应该被填充到与它们在 originatesFrom 中的 nr 相匹配的每个组的底部。 (是的 - 它不会是这里开箱即用的东西 :-/)

我试图通过按 originatesFrom 对它们进行分组来开始,但我确实需要将它们分开,以便我可以单独对它们进行排序(我认为?),而且我不确定使用 linq 是否明智,而不是一次一个地遍历所有对象,构建多个列表并最终将它们连接起来?

好处是很少会有真正的对象(所以效率可能不是什么大问题)。在排序之前我不会知道会有多少组,以及每个组中有多少对象。

如果我需要更好地解释排序规则,请告诉我!

最佳答案

假设这实际上是在 List<T> 中或类似的(而不是通过 IQueryable<T> 我们可能需要担心查询是否可以翻译),我相信这应该有效:

  • 分组依据“originatesFrom 如果非空;nr 否则”
  • 将每个组转换成一个列表,在 originatesFrom 上排序(降序)然后按 lastChanged (降序)- 这将保留 null originatesFrom最后
  • 按第一项的“lastChanged”(升序)对列表进行排序
  • SelectMany 压平

这是一个包含示例输入数据的完整示例:

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

class Test
{
    static void Main()
    {
        var items = new[]
        {
             new { Number = 1, OriginatesFrom = (int?) null, LastChanged = new DateTime(2018,5,3) },
             new { Number = 2, OriginatesFrom = (int?) null, LastChanged = new DateTime(2018,5,3) },
             new { Number = 3, OriginatesFrom = (int?) null, LastChanged = new DateTime(2018,5,3) },
             new { Number = 4, OriginatesFrom = (int?) 1, LastChanged = new DateTime(2018,5,1) },
             new { Number = 5, OriginatesFrom = (int?) 2, LastChanged = new DateTime(2018,5,1) },
             new { Number = 6, OriginatesFrom = (int?) 1, LastChanged = new DateTime(2018,5,7) },
             new { Number = 7, OriginatesFrom = (int?) 1, LastChanged = new DateTime(2018,5,4) },
             new { Number = 8, OriginatesFrom = (int?) 3, LastChanged = new DateTime(2018,5,13) },
             new { Number = 9, OriginatesFrom = (int?) 1, LastChanged = new DateTime(2018,5,13) },
             new { Number = 10, OriginatesFrom = (int?) 3, LastChanged = new DateTime(2018,5,10) },
             new { Number = 11, OriginatesFrom = (int?) 3, LastChanged = new DateTime(2018,5,18 )}
        };

        var query = items
            .GroupBy(x => x.OriginatesFrom ?? x.Number)
            .Select(g => g.OrderByDescending(x => x.OriginatesFrom)
                          .ThenByDescending(x => x.LastChanged)
                          .ToList())
            .OrderBy(g => g.First().LastChanged)
            .SelectMany(g => g)
            .ToList();

        foreach (var item in query)
        {
            Console.WriteLine(item);
        }        
    }
}

输出,符合您要求的顺序:

{ Number = 5, OriginatesFrom = 2, LastChanged = 01/05/2018 00:00:00 }
{ Number = 2, OriginatesFrom = , LastChanged = 03/05/2018 00:00:00 }
{ Number = 9, OriginatesFrom = 1, LastChanged = 13/05/2018 00:00:00 }
{ Number = 6, OriginatesFrom = 1, LastChanged = 07/05/2018 00:00:00 }
{ Number = 7, OriginatesFrom = 1, LastChanged = 04/05/2018 00:00:00 }
{ Number = 4, OriginatesFrom = 1, LastChanged = 01/05/2018 00:00:00 }
{ Number = 1, OriginatesFrom = , LastChanged = 03/05/2018 00:00:00 }
{ Number = 11, OriginatesFrom = 3, LastChanged = 18/05/2018 00:00:00 }
{ Number = 8, OriginatesFrom = 3, LastChanged = 13/05/2018 00:00:00 }
{ Number = 10, OriginatesFrom = 3, LastChanged = 10/05/2018 00:00:00 }
{ Number = 3, OriginatesFrom = , LastChanged = 03/05/2018 00:00:00 }

LINQ 是不是很棒?

关于c# linq 相当复杂的排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52290179/

相关文章:

c# - 为什么这个方法会导致无限循环?

entity-framework - EntityFunctions.AsNonUnicode 等同于 .NET Core

c# - System.String ElementAt[String](System.Collections.Generic.IEnumerable`1[System.String], Int32)' 方法

根据哈希表的条目值(而不是键)对哈希表进行排序

c# - 虽然想要创建 SIFTDetector : Get an Attempted to read or write protected memory exception Error 的实例

c# - .NET 中的 ApplicationException 是什么?

c# - 如何更改 DateTime 对象在 DataGridView 中的显示方式

c# - 根据条件删除具有多个id的记录

python - 对列表中的元素子列表进行排序,将其余元素留在原地

c++ - 如何对整数进行排序并将它们放在列表中