2011-02-23 50 views
1

我期待從以下約束對Dictionary<string, DateTime>創建批次:C#LINQ - 排序和分組一個詞典<字符串,日期時間>日期與最大羣規模

  1. 所有項目在批多少份額相同日期
  2. 單個批次中不能多於X個項目。如果有更多的日期相同的項目,則必須創建另一批次。

我已經制定了以下邏輯,但想知道是否有其他更簡潔的方式來做到這一點只是linq。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace dictionary_sort_by_value_test 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      int maxBatchSize = 3; 

      Dictionary<string, DateTime> secs = new Dictionary<string, DateTime>(); 
      secs.Add("6571 JT", new DateTime(2011, 1, 10)); 
      secs.Add("6572 JT", new DateTime(2011, 1, 12)); 
      secs.Add("6573 JT", new DateTime(2011, 1, 12)); 
      secs.Add("6574 JT", new DateTime(2011, 1, 12)); 
      secs.Add("6575 JT", new DateTime(2011, 1, 10)); 
      secs.Add("6576 JT", new DateTime(2011, 1, 11)); 
      secs.Add("6577 JT", new DateTime(2011, 1, 11)); 
      secs.Add("6578 JT", new DateTime(2011, 1, 11)); 
      secs.Add("6579 JT", new DateTime(2011, 1, 11)); 

      var sorted = secs.OrderBy(o => o.Value).GroupBy(o => o.Value); 

      foreach (var date in sorted) 
      {  
       Console.Write("\nNew batch at {0} \n", date.Key); 
       int batchsize = 0; 
       foreach (var sec in date) 
       { 
        if (batchsize < maxBatchSize) 
        { 
         Console.Write(" {0} {1} \n", sec.Key, sec.Value); 
         batchsize++; 
        } 
        else 
        { 
         Console.Write("\nNew batch at {0} \n", date.Key); 
         Console.Write(" {0} {1} \n", sec.Key, sec.Value); 
         batchsize = 1; 
        } 
       } 
      } 
     } 
    } 
} 
+0

我看不出哪裏/你如何創造你的代碼的新一批無論是。您正在計算批次的數量,但不是每個都創建一個新批次並將其添加到「結果」中。就我個人而言,我唯一能夠僅使用LINQ來做到這一點的方法就是再打破一個平局,這樣你也可以用它來分組。或者在IEnumerable 上實現您的邏輯作爲擴展方法。這樣,它看起來像LINQ,感覺像LINQ,它將是LINQ,因爲無論如何這都是LINQ的實現方式。 – 2011-02-23 11:11:18

回答

1

您可以按照您的密鑰進行分組,然後在結果中按項目索引進行分組,然後再除以所需的塊大小。

var chunkSize = 3; 
var sorted = secs 
    .OrderBy(kv => kv.Key) 
    .GroupBy(o => o.Value) 
    .Select(g => new {Chunks = g.Select((o,i) => new {Val = o, Index = i}) 
           .GroupBy(item => item.Index/chunkSize)}); 

並顯示它:

foreach(var item in sorted.SelectMany(item => item.Chunks)) 
{ 
    Console.WriteLine("New batch at " + item.First().Val.Value); 
    foreach(var element in item) 
     Console.WriteLine(element.Val.Key); 
} 
+0

謝謝。這正是我所期待的。 – 2011-02-24 01:26:51

0

不嚴格使用LINQ來解決你的問題,但處理迭代更簡潔的方式:你可以用2個GroupBys做

static void Main(string[] args) 
{ 
    int maxBatchSize = 3; 

    Dictionary<string, DateTime> secs = new Dictionary<string, DateTime>(); 
    secs.Add("6571 JT", new DateTime(2011, 1, 10)); 
    secs.Add("6572 JT", new DateTime(2011, 1, 12)); 
    secs.Add("6573 JT", new DateTime(2011, 1, 12)); 
    secs.Add("6574 JT", new DateTime(2011, 1, 12)); 
    secs.Add("6575 JT", new DateTime(2011, 1, 10)); 
    secs.Add("6576 JT", new DateTime(2011, 1, 11)); 
    secs.Add("6577 JT", new DateTime(2011, 1, 11)); 
    secs.Add("6578 JT", new DateTime(2011, 1, 11)); 
    secs.Add("6574 JT", new DateTime(2011, 1, 11)); 
    secs.Add("6579 JT", new DateTime(2011, 1, 11)); 
    secs.Add("6580 JT", new DateTime(2011, 1, 11)); 
    secs.Add("6581 JT", new DateTime(2011, 1, 11)); 
    secs.Add("6582 JT", new DateTime(2011, 1, 11)); 
    secs.Add("6583 JT", new DateTime(2011, 1, 11)); 

    secs.OrderBy(o => o.Value).GroupBy(o => o.Value).ToList().ForEach(date => 
        { 
         Console.Write("\nNew batch at {0} \n", date.Key); 
         int batchsize = 0; 
         foreach (var sec in date) 
         { 
          if (batchsize >= maxBatchSize) 
          { 
           Console.Write("\nNew batch at {0} \n", date.Key); 
           batchsize = 0; 
          } 

          Console.Write(" {0} {1} \n", sec.Key, sec.Value); 
          batchsize++; 
         } 
        }); 

    Console.ReadLine(); 
} 
0

。首先按DateTime進行分組,然後逐頁分組。我不得不明確地指定通用參數,因爲編譯器選擇了錯誤的重載,並且使得查詢代碼更長。

var groups = secs.GroupBy<KeyValuePair<string, DateTime>, DateTime, string, Group>(
    p => p.Value, 
    p => p.Key, 
    (d, g) => new Group { 
     Date = d, 
     Pages = g.Select((s, i) => new KeyValuePair<string, int>(s, i/maxBatchSize)) 
      .GroupBy<KeyValuePair<string, int>, int, string, Page>(
       p => p.Value, 
       p => p.Key, 
       (p, g2) => new Page { Id = p, Items = g2.ToList() }) }); 

foreach (var group in groups) 
{ 
    Console.WriteLine("Date: {0}", group.Date); 
    foreach (var page in group.Pages) 
    { 
     Console.WriteLine("Page: {0}", page.Id); 
     foreach (var key in page.Items) 
      Console.WriteLine(key); 
    } 
} 

正如你所看到的,我不得不定義2類,因爲正如我所說,我必須指定通用參數,因爲使用匿名類型做了重載解析選擇另一個超載。

class Group 
{ 
    public DateTime Date; 
    public IEnumerable<Page> Pages; 
} 

class Page 
{ 
    public int Id; 
    public IEnumerable<string> Items; 
} 

希望這會有所幫助。