2014-01-22 3 views
2

Я хотел бы знать, как группировать пункт и разделить каждый N запись с помощью 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 

Спасибо за ваши помощь снова

+1

возможно дубликат [ Как использовать Linq для группировки каждого N числа строк] (http: // stackoverflow.com/questions/860305/how-to-use-linq-to-group-every-n-number-of-rows) – Rawling

+0

Возможно, третий элемент должен быть 'ITEM001 | 30' если у вас есть 23 ITEM001? –

+0

Да. Моя ошибка ввода. следующий вопрос, как сгруппировать список, если count not> = 10? В результате ITEM01: 100, ITEM01: 100, ITEM01: 10, ITEM01: 10, ITEM01: 10, ITEM02: 50, ITEM02: 50 –

ответ

2
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) расширение Batch или написать свой собственный один:

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.

+0

@ KonradKokosa, как я могу видеть из примера, OP хочет элементы, сгруппированные по имени в партиях с максимальным размером 10 (то есть это относится к количеству элементов вместо общего количества) –

+0

Оно работает! Но могу ли я задать еще один вопрос? как сгруппировать список, если count not> = 10? Ожидайте результат, ITEM01: 100, ITEM01: 100, ITEM01: 10, ITEM01: 10, ITEM01: 10, ITEM02: 50, ITEM02: 50 –

0

Примечание:.. Ниже ответ группы элементов по сумме, не рассчитывайте тем не менее, я оставляю его здесь на будущем может быть кто-то когда-нибудь подобная проблема

Вы можете достичь его. следующий запрос 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 
+0

Он хочет, чтобы он был разбит по счету (каждая группировка должна содержать только 10 элементов), а не суммой , –

+0

@ledbutter, true, ясно, что я неправильно понял вопрос. –

Смежные вопросы