views:

133

answers:

3

I've got the following code:

List<Person> people = new List<Person>
    {
     new Person{ Id = 1, Name = "Bob"},
     new Person{ Id = 2, Name = "Joe"},
     new Person{ Id = 3, Name = "Bob"}
    };

    var peopleGroupedByName = from p in people 
                              group p by p.Name;

    //get all groups where the number of people in the group is > 1

For the life of me I can't figure out how to work with the values returned by the linq query to be able to then filter all of the groups that were returned so that I only have the groups that have more than one item in them.

At the moment I'm banging my head against a wall and I can't quite think of what keywords to use in a google search in order to figure it out for myself.

I'd really appreciate any help on how to do this in Linq cause it seems like it should be very simple to do.

+2  A: 
var peopleGroupedByName = people.GroupBy(p => p.Name)
                                .Where(g => g.Count() > 1);

var peopleGroupedByName = from p in people 
                          group p by p.Name into g
                          where g.Count() > 1
                          select g;
Mehrdad Afshari
Is it possible to do it in the comprehension syntax?
mezoid
Yeah, of course. Just add `where g.Count() > 1` to your query.
Mehrdad Afshari
+4  A: 
List<Person> people = new List<Person> {
    new Person{ Id = 1, Name = "Bob"},
    new Person{ Id = 2, Name = "Joe"},
    new Person{ Id = 3, Name = "Bob"}
};

var peopleGroupedByName = from p in people 
                          group p by p.Name into peopleGroup
                          where peopleGroup.Count() > 1
                          select peopleGroup;

//get all groups where the number of people in the group is > 1

Alternatively, where peopleGroup.Skip(1).Any() as Mehrdad has suggested will generally provide better performance with Linq to Objects since Count() iterates over the entire group's contents, and Skip(1).Any() merely over the first 2 elements - (see his comment for details; Count is fine for group-by clauses).

Aside: For readability, I prefer consistently using either the .GroupBy(... extension method syntax or the group ... by ... into ... query syntax but not both.

Eamon Nerbonne
ah! into! of course! that's what I was missing! thanks Eamon.
mezoid
Eamon: Re `.Skip(1).Any()`: it *generally* improves performance. To be accurate, if the collection does not implement `ICollection<T>` and provide a `Count` property that returns the count in O(1), it improves performance. However, for this specific case, `Grouping` class, which is an `internal` class in `System.Core`, implements `Count` as O(1) so `.Count() > 1` is preferred.
Mehrdad Afshari
Thanks for the detailed info!
Eamon Nerbonne
A: 

This is actually quite easy.

var filtererGroups = people
    .GroupBy(p => p.Name)
    .Where(grp => grp.Count() > 1);

To filter by key you would do something like that.

var filtererGroups = people
    .GroupBy(p => p.Name)
    .Where(grp => grp.Key == "Bob");
Daniel Brückner