Coder Perfect

In LINQ, group by

Problem

Let’s say we have a class called:

class Person { 
    internal int PersonID; 
    internal string car; 
}

I’ve made a list of the students in this class: Persons in a list;

And, for example, this list can have many instances with the same PersonIDs:

persons[0] = new Person { PersonID = 1, car = "Ferrari" }; 
persons[1] = new Person { PersonID = 1, car = "BMW"     }; 
persons[2] = new Person { PersonID = 2, car = "Audi"    }; 

Is there a way to get a list of all the cars he owns by grouping by PersonID?

The expected outcome, for example, would be

class Result { 
   int PersonID;
   List<string> cars; 
}

So, after grouping, I’d have:

results[0].PersonID = 1; 
List<string> cars = results[0].cars; 

result[1].PersonID = 2; 
List<string> cars = result[1].cars;

So far, I’ve done the following:

var results = from p in persons
              group p by p.PersonID into g
              select new { PersonID = g.Key, // this is where I am not sure what to do

I’d appreciate it if someone could lead me in the correct place.

Asked by test123

Solution #1

Without a doubt, you’re looking for:

var results = from p in persons
              group p.car by p.PersonId into g
              select new { PersonId = g.Key, Cars = g.ToList() };

Alternatively, as a non-query expression:

var results = persons.GroupBy(
    p => p.PersonId, 
    p => p.car,
    (key, g) => new { PersonId = key, Cars = g.ToList() });

When regarded as an IEnumerableT>, the contents of the group are just a sequence of whatever values were present in the projection (p.car in this case) for the given key.

See my Edulinq post on the subject for more information on how GroupBy works.

(To comply with.NET naming rules, I’ve renamed PersonID to PersonId in the above.)

Another option is to utilize a Lookup:

var carsByPersonId = persons.ToLookup(p => p.PersonId, p => p.car);

The automobiles for each person can then be simply obtained:

// This will be an empty sequence for any personId not in the lookup
var carsForPerson = carsByPersonId[personId];

Answered by Jon Skeet

Solution #2

var results = from p in persons
              group p by p.PersonID into g
              select new { PersonID = g.Key,
                           /**/car = g.Select(g=>g.car).FirstOrDefault()/**/}

Answered by Tallat

Solution #3

You could also try:

var results= persons.GroupBy(n => new { n.PersonId, n.car})
                .Select(g => new {
                               g.Key.PersonId,
                               g.Key.car)}).ToList();

Answered by shuvo sarker

Solution #4

var results = from p in persons
              group p by p.PersonID into g
              select new { PersonID = g.Key, Cars = g.Select(m => m.car) };

Answered by Yogendra Paudyal

Solution #5

try

persons.GroupBy(x => x.PersonId).Select(x => x)

or

Try to see if any of the people on your list are repeating themselves.

persons.GroupBy(x => x.PersonId).Where(x => x.Count() > 1).Any(x => x)

Answered by Code First

Post is based on https://stackoverflow.com/questions/7325278/group-by-in-linq