【问题标题】:How to group list and split every n records?如何对列表进行分组并拆分每 n 条记录?
【发布时间】:2014-01-23 17:31:12
【问题描述】:

我想知道如何使用 LINQ 对项目进行分组和拆分每 N 条记录

# |ITEM  |QUANTITY
==================
1 |ITEM01| 10
2 |ITEM01| 10
3 |ITEM01| 10
.     .     .
.     .     .
22|ITEM01| 10
23|ITEM02| 50
24|ITEM02| 50

假设有一个包含 23 个 ITEM001 和 2 个 ITEM002 的列表

如何获得

ITEM  |QUANTITY
=================
ITEM001 | 100
ITEM001 | 100
ITEM001 | 20
ITEM002 | 100

按ITEM分组,如果分组> 10,则转到下一个

有什么方法可以实现吗?感谢您的帮助!

感谢这些好人的帮助!进一步的问题,现在我想对列表进行分组(每10条记录分组,分组后,如果计数未达到10,则不要分组),对不起我的英语不好:(

ITEM  |QUANTITY
=================
ITEM01 | 100
ITEM01 | 100
ITEM01 | 10
ITEM01 | 10
ITEM01 | 10
ITEM02 | 50
ITEM02 | 50

再次感谢您的帮助!

【问题讨论】:

  • 如果您有 23 个 ITEM001,也许第三项应该是 ITEM001 | 30
  • 是的。我的打字错误。进一步的问题,如果计数不> = 10,如何对列表进行分组?结果,ITEM01:100,ITEM01:100,ITEM01:10,ITEM01:10,ITEM01:10,ITEM02:50,ITEM02:50

标签: c# linq


【解决方案1】:
var query = 
    items.GroupBy(item => item.Name)
         .SelectMany(g => g.Select((item, index) => new { item, index })
                           .GroupBy(x => x.index / 10)
                           .Select(batch => new Item { 
                                 Name = batch.First().item.Name, 
                                 Quantity = batch.Sum(x => x.item.Quantity) 
                            })).OrderBy(item => item.Name);
  1. 按名称对所有项目进行分组。这将为您的示例数据提供两组。
  2. 将每组按 10 个项目分成批次,并从每个批次中选择新的聚合项目(批次可以包含少于 10 个项目,作为 ITEM001 的第三个批次)。
  3. 按项目名称排序结果。

如果您将使用MoreLINQ(可从 NuGet 获得)批处理扩展或编写您自己的,则可以简化此查询:

var query = 
    items.GroupBy(item => item.Name)
         .SelectMany(g => g.Batch(10)
                           .Select(batch => new Item { 
                                 Name = batch.First().Name, 
                                 Quantity = batch.Sum(item => item.Quantity) 
                            })).OrderBy(item => item.Name);

假设你有这样的物品类

public class Item
{
    public string Name { get; set; }
    public int Quantity { get; set; }
}

然后是这个示例项目列表(使用NBuilder 构建):

var items = Builder<Item>.CreateListOfSize(32)
                         .TheFirst(23)
                             .With(i => i.Name = "ITEM01")
                             .And(i => i.Quantity = 10)
                         .TheNext(9)
                             .With(i => i.Name = "ITEM02")
                             .And(i => i.Quantity = 50)
                         .Build();

会给出结果:

[
  { Name: "ITEM01", Quantity: 100 },  
  { Name: "ITEM01", Quantity: 100 },
  { Name: "ITEM01", Quantity: 30  },
  { Name: "ITEM02", Quantity: 450 }
]

注意:在这种情况下,@Thejaka 解决方案将为您提供五个项目 - 将有两个 ITEM02 项目,数量分别为 350 和 100。

【讨论】:

  • @KonradKokosa 正如我从样本中看到的那样,OP 想要按名称分组的商品,批量最大 10 件(即它指的是商品数量而不是总数量)
  • 有效!但我可以再问一个问题吗?如果计数不> = 10,如何对列表进行分组?预期结果,ITEM01:100,ITEM01:100,ITEM01:10,ITEM01:10,ITEM01:10,ITEM02:50,ITEM02:50
【解决方案2】:

注意: 下面的答案按总和而不是计数对项目进行分组。不过,我将其留在这里以供将来参考。也许有人会遇到类似的问题。

您可以使用以下 LINQ 查询来实现它:

List<Item> items = new List<Item>()
{
    new Item() { Name = "Item01", Quantity = 40 }, // 130
    new Item() { Name = "Item01", Quantity = 70 },
    new Item() { Name = "Item01", Quantity = 10 },
    new Item() { Name = "Item01", Quantity = 10 },
    new Item() { Name = "Item02", Quantity = 50 }, // 100
    new Item() { Name = "Item02", Quantity = 50 },
    new Item() { Name = "Item03", Quantity = 10 }  // 10
};

var result =
    // Group by Name, calculate total sum for each group
    items.GroupBy(i => i.Name, (k, v) => new Item()
    {
        Name = k,
        Quantity = v.Sum(i => i.Quantity)
    })
    // Split groups into 100 packages
    .SelectMany(i => Enumerable.Range(0, (int)Math.Ceiling(i.Quantity / 100.0))
                               .Select(n => new Item()
    {
        Name = i.Name,
        Quantity = i.Quantity > ((n + 1) * 100) ? 100 : i.Quantity - n * 100
    }))
    .ToList();

那么列表中有四个元素:

Item01 100
Item01 30
Item02 100
Item03 10

【讨论】:

  • 他希望它按计数拆分(每个分组应该只有 10 个元素),而不是按总和。
猜你喜欢
  • 2018-07-27
  • 1970-01-01
  • 1970-01-01
  • 2019-02-10
  • 2021-11-22
  • 1970-01-01
  • 2015-01-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多