C# 在使用双重分组后,如何展平Linq查询?

C# 在使用双重分组后,如何展平Linq查询?,c#,linq,C#,Linq,假设我有一个表示订单行的类,例如 public class Line { public string Code ; public string No ; // Invoice Number public DateTime Date ; public string Product ; public decimal Quantity ; } 和一系列行,如 List<Line> myList = new List<Line>(); m

假设我有一个表示订单行的类,例如

public class Line
{
    public string Code ;
    public string No ; // Invoice Number
    public DateTime Date ;
    public string Product ;
    public decimal Quantity ;
}
和一系列行,如

List<Line> myList = new List<Line>();
myList.Add(new Line() { Code = "ABC001", No = "1001" ,Date = new DateTime(2012,4,1) ,  Product = "X", Quantity= 1m});
myList.Add(new Line() { Code = "ABC001", No = "1001" ,Date = new DateTime(2012,4,1) ,  Product = "Y", Quantity= 1m});

myList.Add(new Line() { Code = "ABC002", No = "1002" ,Date = new DateTime(2012,4,2) ,  Product = "X", Quantity= 1m});
myList.Add(new Line() { Code = "ABC002", No = "1002" ,Date = new DateTime(2012,4,2) ,  Product = "Y", Quantity= 1m});
myList.Add(new Line() { Code = "ABC002", No = "1003" ,Date = new DateTime(2012,4,3) ,  Product = "Z", Quantity= 1m});
myList.Add(new Line() { Code = "ABC002", No = "1004" ,Date = new DateTime(2012,4,4) ,  Product = "X", Quantity= 1m});

myList.Add(new Line() { Code = "ABC003", No = "1005" ,Date = new DateTime(2012,4,4) ,  Product = "X", Quantity= 1m});
myList.Add(new Line() { Code = "ABC003", No = "1006" ,Date = new DateTime(2012,4,4) ,  Product = "X", Quantity= 1m});
myList.Add(new Line() { Code = "ABC003", No = "1006" ,Date = new DateTime(2012,4,4) ,  Product = "Y", Quantity= 1m});
query1现在包含正确的记录,但被包装在iGroup中,我很难将结果作为
列表导出

我试过了 query1.SelectMany(r=>r.Results.ToList()

但这仍然让我不得不分组,这就是我被困的地方

我可以使用嵌套for循环,如中所示

List<Line> output = new List<Line>();
foreach (var r1 in query1)
{
    foreach(var r2 in r1.Results)
        foreach(var r3 in r2)
            output.Add(r3);     
}

你要踢自己了:

query1.SelectMany(q => q);

ABC002 1003 3/04/2012 12:00:00 AM Z 1 
ABC002 1004 4/04/2012 12:00:00 AM X 1 
ABC003 1006 4/04/2012 12:00:00 AM X 1 
ABC003 1006 4/04/2012 12:00:00 AM Y 1 
来自
query1
的返回是
IGrouping
的可枚举(我删除了您的列表),而
IGrouping
本身就是可枚举的,因此我们可以直接将其展平

请看这里:

编辑:记得我还简化了您的代码:

var query1 = 
(from r in myList
    group r by new { r.Code ,  r.No , r.Date } into results
    group results by new { results.Key.Code } into results2 
    where results2.Count() > 1
    from result in results2.OrderBy(i=>i.Key.Date).Skip(1)
    select result
 );
试试这个:

var flattenedLines = from outerGroup in query1
                     from innerGroup in outerGroup.Results
                     from line in innerGroup
                     select line;

此代码:

List<Line> output = new List<Line>(); 
foreach (var r1 in query1) 
  foreach(var r2 in r1.Results)         
    foreach(var r3 in r2)
      output.Add(r3);   

我会将
results2.ToList().OrderBy(I=>I.Key.Date).跳过(1).ToList()
更改为
results2.OrderBy(I=>I.Key.Date).跳过(1).ToList()
。没有理由第一次调用
ToList()
。@phoog我已经删除了第一个ToList(),因为你是正确的,因为它不需要,但也不会影响结果,所以我仍然有我原来的问题。是的,我把它作为一个注释发布,因为它没有回答你的问题。我还在下面贴了一个答案。@NiklasB。否,因为outerGroup.Results是
IEnumerable
,其中
TKey
是定义键的匿名类型。我认为这是OP最初的问题。Yamen展示了如何通过简化
query1
来简化扁平化查询,但是如果我们保持
query1
不变,我们必须有两个SelectMany调用,或者从
子句中有三个
。如果query1.SelectMany(q=>q)在简化我的查询之前起作用,那么我肯定会受到严厉的惩罚,但说实话,我不认为我自己能做到这一点。谢谢。是的,我忘了我简化了查询。在此之前,@phoog给出了正确的答案。不管怎样,诀窍是认识到
i分组
实现了
i编号
var flattenedLines = from outerGroup in query1
                     from innerGroup in outerGroup.Results
                     from line in innerGroup
                     select line;
var flattenedLines = query1
    .SelectMany(outerGroup => outerGroup.Results, (outerGroup, innerGroup) => innerGroup)
    .SelectMany(x => x);
List<Line> output = new List<Line>(); 
foreach (var r1 in query1) 
  foreach(var r2 in r1.Results)         
    foreach(var r3 in r2)
      output.Add(r3);   
var q2 = from r1 in query1
         from r2 in r1.Results
         from r3 in r2
         select r3;
var output = q2.ToList();