按一个属性拆分列表,然后按属性对升序嵌套列表<t>进行排序

时间:2019-02-08 10:55:52

标签: c# linq

我有一个简单的课:

class SimpleDevice 
{
    public string IMEI {get;set;}
    public long Timestamp {get;set;}
}

以及一种用于测试目的生成列表的方法:

private static List<SimpleDevice> GenerateListOfDevices() 
{
    return new List<SimpleDevice>()
    {
        new SimpleDevice { IMEI = "bbbbb", Timestamp = 33 },
        new SimpleDevice { IMEI = "bbbbb", Timestamp = 45 },
        new SimpleDevice { IMEI = "aaaaa", Timestamp = 36 },
        new SimpleDevice { IMEI = "aaaaa", Timestamp = 37 },
        new SimpleDevice { IMEI = "aaaaa", Timestamp = 35 },
        new SimpleDevice { IMEI = "bbbbb", Timestamp = 34 },
        new SimpleDevice { IMEI = "aaaaa", Timestamp = 39 },
        new SimpleDevice { IMEI = "aaaaa", Timestamp = 38 },
        new SimpleDevice { IMEI = "bbbbb", Timestamp = 35 }
    };
}

我想将List<SimpleDevice>分成List<List<SimpleDevice>>,其中嵌套列表按IMEI分组。

然后,我想按内部列表的Timestamp对其进行排序,因此我对每个列表都有一个顺序输出。

这是我的LINQ声明:

private static List<List<SimpleDevice>> SplitAndSort (List<SimpleDevice> devices)
{
    return devices
            .Select(x => x)
            .GroupBy(x => x.IMEI)
            .Select(x => x.Select(y => y).ToList())
            .OrderBy(x => x.Select(y => y.Timestamp))
            .ToList();
}

哪个抛出以下异常:

  

内部异常System.ArgumentException:至少一个对象必须实现IComparable

OrderBy(x => x.Select(y => y.Timestamp))中发生了什么。

我有一个Google,发现OrderedBy所在的类型必须实现IComparable,而long类型可以做到:

public struct Int64 : IComparable, IComparable<Int64>, ...

将内部x => x.Select(...内的OrderBy更改为x => x.Min(...可以编译和运行我的代码,但是内部列表并未按其Timestamp进行排序拆分工作:

IMEI: bbbbb, Timestamp: 33
IMEI: bbbbb, Timestamp: 45
IMEI: bbbbb, Timestamp: 34
IMEI: bbbbb, Timestamp: 35
IMEI: aaaaa, Timestamp: 36
IMEI: aaaaa, Timestamp: 37
IMEI: aaaaa, Timestamp: 35
IMEI: aaaaa, Timestamp: 39
IMEI: aaaaa, Timestamp: 38

尝试按升序排列内部列表时,我是否缺少明显的东西?

4 个答案:

答案 0 :(得分:3)

您的查询有点混乱。 您将OrderBy放在错误的位置-它在外部列表而不是内部列表上起作用。因此,例外。

在选择(生成)嵌套列表时进行排序:

private static List<List<SimpleDevice>> SplitAndSort(List<SimpleDevice> devices)
{
    return devices
                .GroupBy(x => x.IMEI)
                .Select(g => g.Select(y => y).OrderBy(x => x.Timestamp).ToList())
                .ToList();
}

请注意,取出.Select(y=>y)OrderBy就足够了。 (我没有在上面删除)

答案 1 :(得分:2)

以下应做您想做的事:

private static List<List<SimpleDevice>> SplitAndSort (List<SimpleDevice> devices)
{
    return devices
            .GroupBy(x => x.IMEI)
            .Select(x => x.OrderBy(y=> y.TimeStamp).ToList())
            .ToList();
}

让我引导您完成它:

.GroupBy(x => x.IMEI)

1。通过IMEI对列表进行分组。您现在有了一个类型为IEnumerable >的对象,只需要将ToList匹配即可。

.Select(x => x.OrderBy(y=> y.TimeStamp).ToList())
  1. 在每个组中,按时间戳顺序排序,然后调用ToList()来给您内部列表。此时,您具有IEnumerable >

    类型的对象

    .ToList();

  2. 最后一个ToList将为您提供List >

  3. 的返回类型

答案 2 :(得分:2)

好吧,让我试着向你扔这个。

首先,您要确保列表为ordered by Timestamp,因此现在您知道列表顺序是正确的,然后执行GroupBy和。Select(x => x.Select(y => y).ToList()),这将给出您List<List<SimpleDevice>>

    List<List<SimpleDevice>> test =  devices
        .OrderBy(x=> x.Timestamp)
        .GroupBy(x => x.IMEI)
        .Select(x => x.Select(y => y).ToList())
        .ToList();

这是结果

bbbbb 33
bbbbb 34
bbbbb 35
bbbbb 45
aaaaa 35
aaaaa 36
aaaaa 37
aaaaa 38
aaaaa 39

答案 3 :(得分:0)

第二个选择将生成列表列表。 Order by还选择一个列表作为比较值,该列表未实现IComparable。如果您添加.FirstOrDefault ()或类似名称,则可以使用。

devices
   .GroupBy(x => x.IMEI)
   .Select(x => x.OrderBy(y => y.Timestamp).ToList()) // <- order inner list here
   //.OrderBy(x => x.Select(y => y.Timestamp)) // you don't need this line then
   .ToList();