Advertisement
Advertisement


Group by in LINQ


Question

Let's suppose if we have a class like:

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

I have a list of this class: List<Person> persons;

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

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 I can group by PersonID and get the list of all the cars he has?

For example, the expected result would be

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

So after grouping, I would get:

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

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

From what I have done so far:

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

Could someone please point me in the right direction?

2020/06/11
1
1078
6/11/2020 8:49:54 AM

Accepted Answer

Absolutely - you basically want:

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

Or as a non-query expression:

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

Basically the contents of the group (when viewed as an IEnumerable<T>) is a sequence of whatever values were in the projection (p.car in this case) present for the given key.

For more on how GroupBy works, see my Edulinq post on the topic.

(I've renamed PersonID to PersonId in the above, to follow .NET naming conventions.)

Alternatively, you could use a Lookup:

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

You can then get the cars for each person very easily:

// This will be an empty sequence for any personId not in the lookup
var carsForPerson = carsByPersonId[personId];
2020/04/06
1763
4/6/2020 3:26:11 PM

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()/**/}
2014/07/24

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

You can also Try this:

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

try

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

or

to check if any person is repeating in your list try

persons.GroupBy(x => x.PersonId).Where(x => x.Count() > 1).Any(x => x)
2018/06/25

I have created a working code sample with Query Syntax and Method Syntax. I hope it helps the others :)

You can also run the code on .Net Fiddle here:

using System;
using System.Linq;
using System.Collections.Generic;

class Person
{ 
    public int PersonId; 
    public string car  ; 
}

class Result
{ 
   public int PersonId;
   public List<string> Cars; 
}

public class Program
{
    public static void Main()
    {
        List<Person> persons = new List<Person>()
        {
            new Person { PersonId = 1, car = "Ferrari" },
            new Person { PersonId = 1, car = "BMW" },
            new Person { PersonId = 2, car = "Audi"}
        };

        //With Query Syntax

        List<Result> results1 = (
            from p in persons
            group p by p.PersonId into g
            select new Result()
                {
                    PersonId = g.Key, 
                    Cars = g.Select(c => c.car).ToList()
                }
            ).ToList();

        foreach (Result item in results1)
        {
            Console.WriteLine(item.PersonId);
            foreach(string car in item.Cars)
            {
                Console.WriteLine(car);
            }
        }

        Console.WriteLine("-----------");

        //Method Syntax

        List<Result> results2 = persons
            .GroupBy(p => p.PersonId, 
                     (k, c) => new Result()
                             {
                                 PersonId = k,
                                 Cars = c.Select(cs => cs.car).ToList()
                             }
                    ).ToList();

        foreach (Result item in results2)
        {
            Console.WriteLine(item.PersonId);
            foreach(string car in item.Cars)
            {
                Console.WriteLine(car);
            }
        }
    }
}

Here is the result:

1
Ferrari
BMW
2
Audi
-----------
1
Ferrari
BMW
2
Audi

2017/11/30

Source: https://stackoverflow.com/questions/7325278
Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Email: [email protected]