简体   繁体   English

按多个条件拆分列表

[英]Split list by multiple conditions

This LINQ and lambda expressions are killing me, so there is me again searching for help here :) 这个LINQ和lambda表达式正在杀了我,所以我再次在这里寻求帮助:)

What I would like to do is transform List<Order> to List<List<Order>> having few things on mind. 我想要做的是将List<Order>转换为List<List<Order>> ,记住一些事情。

There is some class Order with ID, Currency, and Ammount where basicaly only Currency has some role in this question. 有一些具有ID,货币和Ammount的类Order ,其中仅基本货币在此问题中有一些作用。

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

Beside Order class there is some parameter for the maximum size of list. 除了Order类之外,还有一些参数用于列表的最大大小。

int MaxListSize = 3;

And there is the list of orders 还有订单清单

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
}

Transformation should look like this 转型应该是这样的

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

translated to simple language each element of this output list sholud be list that contains only orders of same currency, and the max size of the element list should be param from the begining, MaxListSize. 转换为简单语言此输出列表的每个元素sholud是仅包含相同货币的订单的列表,并且元素列表的最大大小应该是从开始的MaxListSize的参数。

And when I'm here, let's add a little bit more. 当我在这里时,让我们再添加一点。 Lets suppose we have some class OrderGroup which represent one item of output transformation few lines uper, but along with List it has property index. 让我们假设我们有一些类OrderGroup,表示一行输出转换几行uper,但与List一起它有属性索引。

class OrderGroup
{
    List<Order> OrderList
    int ListIndex
}

output should be 输出应该是

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

Output is basicly same as first, plus there is index, which should depend on Currency. 输出与第一个基本相同,加上索引,应该取决于货币。 Each currency has it's own zero based index. 每种货币都有自己的零基指数。

Any help woul be appricieted. 任何帮助都会被高估。 I know it should be somehow done with Select() or SelectMany() extension methods, but I don't know how. 我知道它应该用Select()或SelectMany()扩展方法以某种方式完成,但我不知道如何。

Thanx in advance:) 提前Thanx :)

This is basically @BrokenGlass's answer adding a GroupBy and a SelectMany for completeness: 这基本上是@ BrokenGlass的答案,为完整性添加了GroupBySelectMany

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

To ensure the correct order in general cases, you could add an .OrderBy(o => o.ID) clause at the beginning of the query. 为了确保一般情况下的正确顺序,您可以在查询开头添加.OrderBy(o => o.ID)子句。 But it doesn't matter in your test example. 但是在您的测试示例中无关紧要。

To group your lists something like this should work: 要对列表进行分组,应该使用以下内容:

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

Transforming into an OrderGroup is now easy: 转换为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();

This is a tricky select, but it does what you need it to do: 这是一个棘手的选择,但它做你需要做的事情:

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

Running this produces the following output: 运行此命令会产生以下输出:

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM