Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using LINQ to get all property with the exact same value?

Tags:

c#

linq

I have a list of data like this:

Prod1: Id=1,  Name="Book",    Active=true
Prod2: Id=2,  Name="Book",    Active=false
Prod3: Id=3,  Name="Book",    Active=true
Prod4: Id=4,  Name="Laptop",  Active=true
Prod5: Id=5,  Name="Laptop",  Active=true
Prod6: Id=6,  Name="Laptop",  Active=true

What I want to perform is to get reduced list like this:

Prod1: Id=4, Name="Laptop", Active=true

What I am trying to do is that I need to select all products group by its Name, and return all that has true. Since Book has one false, it should not return Book.

I've tried this one:

lstProducts = lstProducts 
                .Where(x =>
                    lstProducts 
                   .All(c => c.Name == x.Name && c.Active == true))
                .GroupBy(c => c.Name).Select(c => c.First())
                .ToList();

But its returning zero results. If I do a where clause where Active == true, its getting a Book product, which shouldn't since all of its Active should be true in order to get it.

like image 940
Willy David Jr Avatar asked Aug 16 '17 06:08

Willy David Jr


2 Answers

What you are looking for is to first group all items by their Name, then filter only those that have all true for Active and last retrieve the first item for each group:

var result = lstProducts.GroupBy(item => item.Name)
                        .Where(group => group.All(item => item.Active)
                        .Select(group => group.First());

If you want to ensure some ordering for the group, as in your example then:

var result = lstProducts.GroupBy(item => item.Name)
                        .Where(group => group.All(item => item.Active)
                        .Select(group => group.OrderBy(item => item.Id).First());
like image 93
Gilad Green Avatar answered Nov 17 '22 01:11

Gilad Green


Group first, then filter:

lstProducts
    .GroupBy(c => c.Name)
    .Where(g => g.All(c => c.Active))
    .Select(g => g.First())
    .ToList()

GroupBy guarantees that items within groups have the same order with respect to each other as they did before the grouping. If you’d like to choose the element with the minimum id to represent the group and your original list isn’t ordered by id, however, you can use Min instead of First:

lstProducts
    .GroupBy(c => c.Name)
    .Where(g => g.All(c => c.Active))
    .Select(g => g.Min(c => c.Id))
    .ToList()
like image 4
Ry- Avatar answered Nov 17 '22 00:11

Ry-