Home > Enterprise >  linq group list based on condition
linq group list based on condition

Time:08-24

How to break a list based on an condition?

[1,2,3,4,5,6,1,2,3,4,5,6,5,6] into a List<List<T>>

[1,2,3,4,5,6]

[1,2,3,4,5,6,5,6]

for every '1', select all the items after it until the next '1'.

CodePudding user response:

That's a fun question. I couldn't think of a way to do it without declaring one extra variable.

var ints = new [] {1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 5, 6};

int groupNumber = 0;
List<List<int>> groups = ints
    .GroupBy(i => i == 1 ?   groupNumber : groupNumber, i => i, (gn, enumerable) => enumerable.ToList())
    .ToList();

CodePudding user response:

You can use Linq method Aggregate.

var listy = new List<int>() { 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 5, 6 };
listy.Aggregate<int, List<List<int>>>(new List<List<int>>(), (existing, item) => {
    if (item == 1 || !existing.Any())
    {
        existing.Add(new List<int>());
    }
    existing.Last().Add(item);
    return existing;
})

Interactive console output:

List<List<int>>(2) { List<int>(6) { 1, 2, 3, 4, 5, 6 }, List<int>(8) { 1, 2, 3, 4, 5, 6, 5, 6 } }

Things to note:

The Aggregate method specifies a "seed" value, and this will be the return type List<List<int>>. Because the type is different than the list type, the seed type must be explicitly listed. That means this pseudo-function signature is used:

Aggregate<int, TAccumulate>(TAccumulate, (x, y) => { return x; })

The seed is given as a new List<List<int>>. The first iteration this collection will be empty, so a check for that condition is added (!existing.Any()). This happens to require the same logic from the problem (if item == 1), so that condition is also added. Then it's just a matter of appending the current item to the current (i.e., last) list from the result (list of lists).

  • Related