Reputation: 1104
This LINQ and lambda expressions are killing me, so there is me again searching for help here :)
What I would like to do is transform List<Order>
to List<List<Order>>
having few things on mind.
There is some class Order
with ID, Currency, and Ammount where basicaly only Currency has some role in this question.
class Order
{
int ID;
string Currency;
money Ammount
}
Beside Order
class there is some parameter for the maximum size of list.
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.
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.
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.
Thanx in advance:)
Upvotes: 2
Views: 1479
Reputation: 41290
This is basically @BrokenGlass's answer adding a GroupBy
and a SelectMany
for completeness:
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. But it doesn't matter in your test example.
Upvotes: 4
Reputation: 726639
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;
Upvotes: 2
Reputation: 160912
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:
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();
Upvotes: 2