C# LINQ - 对字典进行排序和分组按最大团体人数的日期

发布于 2024-10-19 07:53:48 字数 1942 浏览 1 评论 0原文

我希望从 Dictionary 创建批次,并具有以下约束:

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

I am looking to created batches from a Dictionary<string, DateTime> with the following constraints:

  1. All items in the batch much share the same date
  2. There can be no more than X items in a single batch. If there are more items with the same date, another batch must be created.

I have worked out the following logic, but was wondering if there was some other more succinct way of doing this with just 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;
                    }
                }
            }
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

听不够的曲调 2024-10-26 07:53:48

您可以按键进行分组,然后在结果中按项目索引除以所需的块大小进行分组。

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

You group by your key, then inside the result you group by the item index divided by the desired chunk size.

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

And displaying it:

 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);
}
撩动你心 2024-10-26 07:53:48

不严格使用 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();
}

Not strictly using linq to solve your problems but a more succinct way of handling the iteration:

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();
}
尤怨 2024-10-26 07:53:48

你可以用 2 个 GroupBy 来完成。首先按日期时间分组,然后按页面分组。我必须显式指定通用参数,因为编译器选择了错误的重载,这使得查询代码更长。

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

希望这有帮助。

You can do it with 2 GroupBys. First you group by DateTime, and then group by page. I had to specify the generic arguments explicitly, because the compiler was picking the wrong overload, and that made the query code longer.

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

As you can see, I had to define 2 classes because as I said, I had to specify the generic arguments, because using anonymous types made the overload resolution pick another overload.

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

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

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文