Разделить список по нескольким условиям - PullRequest
2 голосов
/ 25 января 2012

Это LINQ и лямбда-выражения убивают меня, поэтому я снова ищу здесь помощь:)

То, что я хотел бы сделать, это преобразовать List<Order> в List<List<Order>>, имея в виду несколько вещей.

Существует некоторый класс Order с идентификатором, валютой и суммой, где только валюта играет определенную роль в этом вопросе.

class Order
{
    int ID;
    string Currency;
    money Ammount
}

Помимо Order класса есть некоторый параметр для максимального размера списка.

int MaxListSize = 3;

А есть список заказов

List<Order>
{
    1, EUR, 100
    2, EUR, 200
    3, USD, 34
    4, EUR, 12
    5, EUR, 54
    6, USD, 67
    7, EUR, 22
    8, USD, 67
    9, EUR, 89
    10, USD, 64
    11, EUR, 45
    12, USD, 65
    13, USD, 2
    14, EUR, 78
    15, USD, 79
    16, USD, 66
    17, EUR,  3
    18, EUR, 2
}

Преобразование должно выглядеть следующим образом

List<List<Order>>
{
    {1, EUR, 100},  {2, EUR, 200}   {4, EUR, 12}
    {5, EUR, 54},   {7, EUR, 22},   {9, EUR, 89}
    {11, EUR, 45},  {14, EUR, 78},  {17, EUR,  3}
    {18, EUR, 2}
    {3, USD, 34},   {6, USD, 67},   {8, USD, 67}
    {10, USD, 64},  {12, USD, 65},  {13, USD, 2}
    {15, USD, 79},  {16, USD, 66}
}

переводится на простой язык, каждый элемент этого выходного списка должен быть списком, который содержит только ордера одной и той же валюты, а максимальный размер списка элементов должен быть параметром с самого начала, MaxListSize.

А когда я здесь, давайте добавим немного больше. Предположим, у нас есть некоторый класс OrderGroup, который представляет один элемент выходного преобразования на несколько строк выше, но вместе с List он имеет индекс свойства.

class OrderGroup
{
    List<Order> OrderList
    int ListIndex
}

вывод должен быть

List<OrderGroup>
{
     GroupOrder {OrderList = new List<Order> {{1, EUR, 100},    {2, EUR, 200}   {4, EUR, 12}}, ListIndex  = 1}
     GroupOrder {OrderList = new List<Order> {{5, EUR, 54}, {7, EUR, 22},   {9, EUR, 89}},  ListIndex  = 2}
     GroupOrder {OrderList = new List<Order> {{11, EUR, 45},    {14, EUR, 78},  {17, EUR,  3}}, ListIndex  = 3}
     GroupOrder {OrderList = new List<Order> {{18, EUR, 2}}, ListIndex  = 4}
     GroupOrder {OrderList = new List<Order> {{3, USD, 34}, {6, USD, 67},   {8, USD, 67}}, ListIndex  = 1}
     GroupOrder {OrderList = new List<Order> {{10, USD, 64},    {12, USD, 65},  {13, USD, 2}}, ListIndex  = 2}
     GroupOrder {OrderList = new List<Order> {{15, USD, 79},    {16, USD, 66}}, ListIndex  = 3}
}

Вывод в основном такой же, как первый, плюс есть индекс, который должен зависеть от валюты. Каждая валюта имеет свой собственный нулевой индекс.

Любая помощь будет оценена. Я знаю, что это должно быть как-то сделано с помощью методов расширения Select () или SelectMany (), но я не знаю, как.

Заранее спасибо:)

Ответы [ 3 ]

4 голосов
/ 25 января 2012

Это в основном ответ @ BrokenGlass, добавляющий GroupBy и SelectMany для полноты:

var results = orders.GroupBy(o => o.Currency)
                    .SelectMany(g => g.Select((order, index) => new { Index = index, Order = order })
                                      .GroupBy(x => x.Index / MaxListSize)
                                      .Select(og => new OrderGroup() 
                                      {
                                         ListIndex = og.Key,
                                         OrderList = og.Select(x => x.Order).ToList()
                                       })
                                      .ToList())
                    .ToList();

Чтобы обеспечить правильный порядок в общих случаях, вы можете добавить предложение .OrderBy(o => o.ID) в начале запроса. Но это не имеет значения в вашем тестовом примере.

2 голосов
/ 25 января 2012

Это сложный выбор, но он делает то, что вам нужно:

var res = orders
    .GroupBy(o => o.Currency)
    .SelectMany(g => g.Select((o,i) => new {Ind = i, Order = o}))
    .GroupBy(p => new { Num = p.Ind/3, Curr = p.Order.Currency })
    .Select(g => new OrderGroup {ListIndex = g.Key.Num, OrderList = g.Select(x => x.Order).ToList()})
    .ToList();
foreach (var list in res) {
    Console.Write(list.ListIndex);
    foreach (var order in list.OrderList) {
        Console.Write("   {0} {1} {2};", order.ID, order.Currency, order.Ammount);
    }
    Console.WriteLine();
}

Запуск этого дает следующий вывод:

0   1 EUR 100;   2 EUR 200;   4 EUR 12;
1   5 EUR 54;   7 EUR 22;   9 EUR 89;
2   11 EUR 45;   14 EUR 78;   17 EUR 3;
3   18 EUR 2;
0   3 USD 34;   6 USD 67;   8 USD 67;
1   10 USD 64;   12 USD 65;   13 USD 2;
2   15 USD 79;   16 USD 66;
2 голосов
/ 25 января 2012

Для группировки ваших списков должно работать что-то вроде этого:

var orderGroups = orders.Select((order, index) => new { Index = index, Order = order })
                        .GroupBy(x => x.Index / MaxListSize)
                        .Select(g => g.Select(x => x.Order).ToList())
                        .ToList();

Преобразование в OrderGroup теперь легко:

var orderGroups = orders.Select((order, index) => new { Index = index, Order = order })
                        .GroupBy(x => x.Index / MaxListSize)
                        .Select(g => new OrderGroup() 
                         {
                            ListIndex = g.Key,
                            OrderList = g.Select(x => x.Order).ToList())
                         })
                        .ToList();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...