我希望从Dictionary<string, DateTime>
创建具有以下约束的批次:
我已经制定了以下逻辑,但是想知道是否还有一些其他更简洁的方法只需要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 :(得分: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;
}
希望这有帮助。