Linq 转置列表

Linq Transpose List

我有简单对象列表:

 var r = new  List
        {
            new { Id = 1, Value = 2, DateTime = DateTime.Parse("10.10.2014")},
            new { Id = 2, Value = 3, DateTime = DateTime.Parse("10.10.2014")},
            new { Id = 3, Value = 4, DateTime = DateTime.Parse("10.10.2014")},
            new { Id = 1, Value = 5, DateTime = DateTime.Parse("11.10.2014")},
            new { Id = 2, Value = 6, DateTime = DateTime.Parse("11.10.2014")}
        };

我想得到这样的对象:

DateTime    | 1 | 2 | 3 |
10.10.2014  | 2 | 3 | 4 |
11.10.2014  | 5 | 6 |   |

有什么好的 linq 查询吗?也许像 sql 中的 pivot/unpivot?

试试这个:

r.ToLookup(t => t.id, t=>t.DateTime)

如果这不起作用,请通读 this

您希望根据 id 对列表进行分组,然后通过字典对结果列表进行键控。您应该能够使用 GroupBy 和 ToDictionary() 的某种组合来做到这一点,它创建一个分组列表的列表和 ToDictionary(),它创建允许您将对象的 属性 指定为键并从中创建一个字典。

您正在寻找一个简单的 GroupBy:

var result = r.GroupBy(x => x.DateTime)
              .Select (grp => new
               {
                   DateTime = grp.Key,
                   _1 = grp.Where(x => x.Id == 1).Select(x => x.Value).Cast<Int32?>().FirstOrDefault(),
                   _2 = grp.Where(x => x.Id == 2).Select(x => x.Value).Cast<Int32?>().FirstOrDefault(),
                   _3 = grp.Where(x => x.Id == 3).Select(x => x.Value).Cast<Int32?>().FirstOrDefault()
               });

result 现在是:

如果在编译时不知道 ID 的数量,则无法创建 link 语句来将这些 ID 捕获为新字段。 Linq 就可以做到这一点。在这种情况下你能做的最好的是:

var ids = r.Select(x => x.Id).Distinct().OrderBy(x => x).ToArray();

var query =
    from x in r
    group x by x.DateTime into gxs
    let lookup = gxs.ToLookup(x => x.Id, x => (int?)x.Value)
    select new
    {
        DateTime = gxs.Key,
        Values = ids.Select(i => new
        {
            Id = i,
            Value = lookup[i].FirstOrDefault(),
        }).ToArray(),
    };

产生这个:

如果 ID 已知,则以下变体是最佳选择:

var query =
    from x in r
    group x by x.DateTime into gxs
    let lookup = gxs.ToLookup(x => x.Id, x => (int?)x.Value)
    select new
    {
        DateTime = gxs.Key,
        _1 = lookup[1].FirstOrDefault(),
        _2 = lookup[2].FirstOrDefault(),
        _3 = lookup[3].FirstOrDefault(),
    };