6

注文ラインを表すクラスがあるとします。

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});

顧客コードに複数の請求書があるすべての行を取得しようとしています。これを行うには、まずコード、番号、日付でグループ化し、次に顧客コードでグループ化します。2つ以上のレコードがある顧客については、最初のレコードを除くすべてを選択します。

そのようです:

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
        select new 
        {   
            results2.Key.Code , 
            Count = results2.Count(), 
            Results = results2.OrderBy(i=>i.Key.Date).Skip(1).ToList() 
          // Skip the first invoice
        } 
     ).ToList();

query1に正しいレコードが含まれるようになりましたが、IGrouping内にラップされており、結果を次のように取得するのに問題があります。List<Line>

query1.SelectMany(r => r.Results).ToList();を試しました。

しかし、これでもIGroupingが残り、そこで行き詰まります。

のようにネストされた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);     
}

しかし、より良い/ Linqの方法はありますか?

実際の出力は、次のように4行である必要があります。

// Code    No    Date              Product Quantity 
// ABC002 1003 03/04/2012 00:00:00 Z 1 
// ABC002 1004 04/04/2012 00:00:00 X 1 
// ABC003 1006 04/04/2012 00:00:00 X 1 
// ABC003 1006 04/04/2012 00:00:00 Y 1 
4

3 に答える 3

14

あなたは自分自身を蹴るつもりです:

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それ自体が列挙可能であるため、直接フラット化できます。

ここを参照してください:http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2007/09/28/9836.aspx

編集:私もあなたのコードを単純化したことを思い出しました:

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
 );
于 2012-04-26T20:58:14.813 に答える
9

このコード:

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();
于 2012-04-26T20:59:27.783 に答える
3

これを試して:

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);
于 2012-04-26T20:59:19.690 に答える