C#LINQ - 按日期对字典<string,datetime>进行排序和分组,最大组大小为</string,datetime>

时间:2011-02-23 10:39:44

标签: linq datetime sorting group-by

我希望从Dictionary<string, DateTime>创建具有以下约束的批次:

  1. 批次中的所有项目共享相同的日期
  2. 单个批次中只能有X个项目。如果有更多具有相同日期的项目,则必须创建另一个批次。
  3. 我已经制定了以下逻辑,但是想知道是否还有一些其他更简洁的方法只需要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;
                        }
                    }
                }
            }
        }
    }
    

3 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分:0)

不是严格使用linq来解决您的问题,而是使用更简洁的方式来处理迭代:

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

答案 2 :(得分:0)

你可以用2个GroupBys来做。首先按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;
}

希望这有帮助。