组内组 linq

Group inside group linq

我有这样的数据table:

我想将此分组 table 对于 FIELD A 和 FIELD B, 我组的第三个字段应该是FIELD C的列表,但必须按ID字段分组

最后的结果应该是这样的:

First Field | Second Field |  Third Field
------------+--------------+----------------
     5      |     XXXX     |(8) (2,6,3) (9)  
     5      |     KKKK     |(8,3)

第三个字段必须是列表的列表。

我如何使用 LINQ 执行此操作?

到目前为止我试过这个:

        var trytogroup = (from p in datatable.AsEnumerable()
                                group p by new
                                {
                                    ID = p["Id"].ToLong(),
                                    FieldA = p["FieldA"].ToLong(),
                                    FieldB = p["FieldB"].ToString()
                                } into g
                                select new
                                {
                                    FirstField = g.Key.FieldA,
                                    SecondField = g.Key.FieldB,
                                    ThirdField = datatable.AsEnumerable().Where(p => p["FieldA"].ToLong() == g.Key.FieldA && p["FieldB"].ToString() == g.Key.FieldB).Select(p => p["FieldC"].ToLong()).GroupBy(x => x["Id"].ToLong()).Distinct().ToList()
                                });

您的查询有什么问题:

  • 您不需要首先按三个字段分组。按 ID 分组应该在 FieldA 和 FieldB
  • 所拥有的组内完成
  • 获取 ThirdField 时,您无需再次查询数据表 - 您已经拥有所有需要的数据。您只需要按 ID
  • 添加分组

正确查询:

 from r in datatable.AsEnumerable()
 group r by new {
   FieldA = r.Field<long>("FieldA"),
   FieldB = r.Field<string>("FieldB")
 } into g
 select new
 {
     First = g.Key.FieldA,
     Second = g.Key.FieldB,
     Third = g.GroupBy(r => r.Field<long>("ID"))
              .Select(idGroup => idGroup.Select(i => i.Field<long>("FieldC")).ToList())
 }

如果您更喜欢 lambda,您的查询可能如下所示:

dataSource
    .GroupBy(item => new { item.FieldA, item.FieldB })
    .Select(group => new
    {
        First = group.Key.FieldA,
        Second = group.Key.FieldB,
        Third = group.GroupBy(q => q.Id).Select(q => q.Select(e => e.FieldC).ToArray()).ToArray()
    }).ToArray();

只是一些小笔记。 .GroupBy 使用 Lookup 获取 Grouping,因此当不需要延迟执行时,可以通过将 .GroupBy( 替换为 .ToLookup( 来避免一些开销。

每个 Grouping 中的元素都是 stored in array,所以我看不出转换它们有多大用处 .ToList(但你可以节省一点 space如果你转换它们 .ToArray)。

DataTable.AsEnumerable 使用 .Rows.Cast<TRow>(),但在 DataView 通常不需要的排序或过滤时似乎也会做一些额外的事情。

var groups = datatable.Rows.Cast<DataRow>()
    .ToLookup(r => Tuple.Create(
        r["FieldA"] as long?,
        r["FieldB"]?.ToString()
    ))
    .Select(g => Tuple.Create(
        g.Key.Item1, 
        g.Key.Item2,
        g.ToLookup(r => r["ID"] as long?, r => r["FieldC"] as long?)
    )).ToList();

像往常一样,premature optimization is the root of all evil但我认为这些信息可能有用。