Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find consecutive same values items as a Linq group

Tags:

c#

linq

var schedules = new List<Item>{
    new Item { Id=1, Name = "S" },
    new Item { Id=2, Name = "P" },
    new Item { Id=3, Name = "X" },
    new Item { Id=4, Name = "X" },
    new Item { Id=5, Name = "P" },
    new Item { Id=6, Name = "P" },
    new Item { Id=7, Name = "P" },
    new Item { Id=8, Name = "S" }
};

I want to select same values and same orders in a new list like this:

var groupedAndSelectedList = new List<List<Item>>{
    new List<Item> {       
        new Item { Id=3, Name = "X" },
        new Item { Id=4, Name = "X" },
    },
    new List<Item> {       
        new Item { Id=5, Name = "P" },
        new Item { Id=6, Name = "P" },
        new Item { Id=7, Name = "P" },
    }
}

If item is single like new Item { Id=3, Name = "A" } I do not need to get it.

Group by selects all X or P elements in list. But I want if items stands after or before another item.

Is this possible using linq?

like image 938
barteloma Avatar asked Sep 04 '25 03:09

barteloma


1 Answers

What you're looking for here is a GroupWhile<T> method.

Credit to user L.B for the solution. Go give his original answer an UpDoot https://stackoverflow.com/a/20469961/30155

    var schedules = new List<Item>{
        new Item { Id=1, Name = "S" },
        new Item { Id=2, Name = "P" },
        new Item { Id=3, Name = "X" },
        new Item { Id=4, Name = "X" },
        new Item { Id=5, Name = "P" },
        new Item { Id=6, Name = "P" },
        new Item { Id=7, Name = "P" },
        new Item { Id=8, Name = "S" }
    };

    var results = schedules
        .GroupWhile((preceding, next) => preceding.Name == next.Name) 
        //Group items, while the next is equal to the preceding one
        .Where(s => s.Count() > 1)
        //Only include results where the generated sublist have more than 1 element.
        .ToList();

    foreach (var sublist in results)
    {
        foreach (Item i in sublist)
        {
            Console.WriteLine($"{i.Name} - {i.Id}");
        }
        Console.WriteLine("");
    }

    Console.ReadLine();

You can add the implementation as an Extension Method to all IEnumerable<T> like so.

public static class Extensions
{
    public static IEnumerable<IEnumerable<T>> GroupWhile<T>(this IEnumerable<T> seq, Func<T, T, bool> condition)
    {
        T prev = seq.First();
        List<T> list = new List<T>() { prev };

        foreach (T item in seq.Skip(1))
        {
            if (condition(prev, item) == false)
            {
                yield return list;
                list = new List<T>();
            }
            list.Add(item);
            prev = item;
        }

        yield return list;
    }
}
like image 177
Eoin Campbell Avatar answered Sep 06 '25 01:09

Eoin Campbell