2017-01-14 21 views
1

我有如下所述的LINQ查詢。問題是,當該數據是由價格劃分,它日期組的價格,而不考慮可能發生的不連續的日期如何優化LINQ查詢按價格對日期進行分組而不合並結果

價格相同的情況下
using System; 
using System.Collections.Generic; 
using System.Linq; 

public class Program 
{ 
    public static void Main() 
    { 
     //Console.WriteLine("Hello World"); 
     List<Prices> list = new List<Prices>(); 
     list.Add(new Prices() { Date = DateTime.Parse("2017-06-17"), Price = Double.Parse("50")}); 
     list.Add(new Prices() { Date = DateTime.Parse("2017-06-18"), Price = Double.Parse("50")}); 
     list.Add(new Prices() { Date = DateTime.Parse("2017-06-19"), Price = Double.Parse("50")}); 
     list.Add(new Prices() { Date = DateTime.Parse("2017-06-20"), Price = Double.Parse("100")}); 
     list.Add(new Prices() { Date = DateTime.Parse("2017-06-21"), Price = Double.Parse("100")}); 
     list.Add(new Prices() { Date = DateTime.Parse("2017-06-22"), Price = Double.Parse("100")}); 
     list.Add(new Prices() { Date = DateTime.Parse("2017-06-23"), Price = Double.Parse("50")}); 
     list.Add(new Prices() { Date = DateTime.Parse("2017-06-24"), Price = Double.Parse("50")}); 
     list.Add(new Prices() { Date = DateTime.Parse("2017-06-25"), Price = Double.Parse("50")}); 


     var baseservices = list 
       .GroupBy(l => l.Price) 
       .Select(g => new 
       { 
        Price = g.Key, 
        PeriodStart = g.Select(l=>l.Date).Min(), 
        PeriodEnd = g.Select(l => l.Date).Max(), 
       }); 

     foreach(var item in baseservices) 
     { 
      Console.WriteLine(item.Price + " " + item.PeriodStart + " " + item.PeriodEnd); 
     } 

    } 
} 

public class Prices 
{ 
    public DateTime Date {get;set;} 
    public double Price {get;set;} 
} 

public class Quote 
{ 
    public DateTime PeriodStart {get;set;} 
    public DateTime PeriodEnd {get;set;} 
    public double Price {get;set;} 
} 

結果是

50 6/17/2017 12:00:00 AM 6/25/2017 12:00:00 AM 
100 6/20/2017 12:00:00 AM 6/22/2017 12:00:00 AM 

我如何獲得結果如下

50 6/17/2017 12:00:00 AM 6/29/2017 12:00:00 AM 
100 6/20/2017 12:00:00 AM 6/22/2017 12:00:00 AM 
50 6/23/2017 12:00:00 AM 6/25/2017 12:00:00 AM 
+1

使用[moreLINQ](https://www.nuget.org/packages/morelinq)中的「GroupAdjacent」。如果你不想依賴整個pachage,你可能只需複製代碼即可。它的代碼位於GitHub上:https://github.com/morelinq/MoreLINQ/blob/master/MoreLinq/GroupAdjacent.cs。請確保許可證允許在做之前(我不是這裏的專家)。 – MarcinJuraszek

回答

1

如果您的日期範圍創建的幫助類:

public class DateRange 
{ 
    public DateTime PeriodStart { get; set; } 
    public DateTime PeriodEnd { get; set; } 
} 

和幫助方法到列表轉換日期:

public static IEnumerable<DateRange> Convert(IEnumerable<DateTime> dates) 
{ 
    var ret = new DateRange(); 
    foreach (var date in dates) 
    { 
     if (ret.PeriodEnd == default(DateTime)) 
     { 
      ret.PeriodStart = date; 
      ret.PeriodEnd = date; 
     } 
     else if (ret.PeriodEnd.AddDays(1) == date) 
     { 
      ret.PeriodEnd = date; 
     } 
     else 
     { 
      yield return ret; 
      ret = new DateRange(); 
     } 
    } 
    yield return ret; 
} 

您可以將您的日期排序,以期:

var baseservices = list 
     .GroupBy(l => l.Price) 
     .Select(g => new 
     { 
      Price = g.Key, 
      Dates = Convert(g.Select(d=>d.Date)).ToList() 
     }) 
     .SelectMany(r=>r.Dates, (a,b)=>new Quote { 
           Price = a.Price, 
           PeriodStart = b.PeriodStart, 
           PeriodEnd = b.PeriodEnd}) 
     .ToList(); 
+0

upvote for unique approach,but GroupAdjacent http://ideone.com/elughG似乎更容易實現 – mko

3

LINQ是不太適合這樣的操作。可以用來做這樣的處理的唯一標準LINQ運營商Aggregate,但它並不比LINQ十歲上下foreach循環更多:

var baseservices = list 
    .OrderBy(e => e.Date) 
    .Aggregate(new List<Quote>(), (r, e) => 
    { 
     if (r.Count > 0 && r[r.Count - 1].Price == e.Price && r[r.Count - 1].PeriodEnd.AddDays(1) == e.Date) 
      r[r.Count - 1].PeriodEnd = e.Date; 
     else 
      r.Add(new Quote { Price = e.Price, PeriodStart = e.Date, PeriodEnd = e.Date }); 
     return r; 
    }); 

注意,在許多LINQ方法相比,這種執行立即和不返回直到整個結果準備就緒。

+1

不錯,我試圖用聚合來完成它,但是某處用自己寫的方法管理它:) –

相關問題