Question
You have a C# class like this:
class Person
{
internal int PersonID;
internal string car;
}
And a list of Person objects:
List<Person> persons;
This list may contain multiple items with the same PersonID, 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" };
How can you use LINQ to group these items by PersonID and get a list of all cars belonging to each person?
For example, you want a result shape like this:
class Result
{
int PersonID;
List<string> cars;
}
So after grouping, the result would contain one item per PersonID, where each item stores that person's ID and a list of their car names.
You started with:
var results = from p in persons
group p by p.PersonID into g
select new { PersonID = g.Key };
What should be added so that each grouped result also contains the list of car names?
Short Answer
By the end of this page, you will understand how GroupBy works in LINQ, how to group objects by a key such as PersonID, and how to project each group into a new result object containing a list of values like car names.
Concept
GroupBy in LINQ is used when you want to organize a sequence into buckets based on a shared key.
In this example, the key is PersonID. Every Person object with the same PersonID should end up in the same group.
Once the data is grouped, each group gives you:
g.Key— the value used for grouping, such as1or2g— the collection of items inside that group
That means you can do two things after grouping:
- keep the key (
PersonID) - transform the grouped items into something else, such as a
List<string>of car names
This matters in real programming because grouped data appears everywhere:
- orders grouped by customer
- messages grouped by conversation
- products grouped by category
- logs grouped by date or severity
LINQ makes this kind of transformation concise and readable.
Mental Model
Think of GroupBy like sorting papers into folders.
- The folder label is the grouping key, such as
PersonID - Every
Personrecord goes into the folder matching its ID - After that, you open each folder and pull out just the information you need, such as the car names
So for this data:
- Person
1hasFerrariandBMW - Person
2hasAudi
You end up with two folders:
- Folder
1contains two cars - Folder
2contains one car
Syntax and Examples
Basic GroupBy syntax
Query syntax
var results = from p in persons
group p by p.PersonID into g
select new
{
PersonID = g.Key,
Cars = g.Select(x => x.car).ToList()
};
Method syntax
var results = persons
.GroupBy(p => p.PersonID)
.Select(g => new
{
PersonID = g.Key,
Cars = g.Select(x => x.car).ToList()
});
Using a named result class
A real program often uses a named class instead of an anonymous object:
class Result
{
public int PersonID { get; set; }
public List<string> Cars { get; set; }
}
var results = persons
.GroupBy(p => p.PersonID)
.Select(g => new Result
{
PersonID = g.Key,
Cars = g.Select(x => x.car).ToList()
})
.ToList();
Example input and output
Step by Step Execution
Consider this code:
var results = persons
.GroupBy(p => p.PersonID)
.Select(g => new Result
{
PersonID = g.Key,
Cars = g.Select(x => x.car).ToList()
})
.ToList();
And this input:
var persons = new List<Person>
{
new Person { PersonID = 1, car = "Ferrari" },
new Person { PersonID = 1, car = "BMW" },
new Person { PersonID = 2, car = "Audi" }
};
Step 1: GroupBy(p => p.PersonID)
LINQ scans each item and groups them by PersonID.
It creates groups like:
- Group key
1->[Ferrari, BMW] - Group key
2->[Audi]
More precisely:
- Group
1contains twoPersonobjects
Real World Use Cases
Grouping with LINQ is common in many kinds of applications.
Common examples
- E-commerce: group orders by customer ID
- Chat apps: group messages by conversation ID
- School systems: group students by class or department
- Analytics: group events by day, user, or event type
- Inventory systems: group products by category
- Finance apps: group transactions by account
Example: orders by customer
var groupedOrders = orders
.GroupBy(o => o.CustomerId)
.Select(g => new
{
CustomerId = g.Key,
OrderIds = g.Select(o => o.Id).ToList()
});
Example: logs by severity
var groupedLogs = logs
.GroupBy(log => log.Level)
.Select(g => new
{
Level = g.Key,
Messages = g.Select(log => log.Message).ToList()
});
The same idea is used in your PersonID and car example.
Real Codebase Usage
In real projects, developers often combine GroupBy with projection and cleanup steps.
Common patterns
Group and project into DTOs
Instead of keeping raw grouped objects, developers usually create a result type:
var results = persons
.GroupBy(p => p.PersonID)
.Select(g => new Result
{
PersonID = g.Key,
Cars = g.Select(p => p.car).ToList()
})
.ToList();
This is cleaner for APIs, services, and UI models.
Remove duplicates inside groups
If one person might have the same car listed multiple times:
var results = persons
.GroupBy(p => p.PersonID)
.Select(g => new Result
{
PersonID = g.Key,
Cars = g.Select(p => p.car).Distinct().ToList()
})
.ToList();
Filter before grouping
You may only want valid rows:
var results = persons
.Where(p => !string.IsNullOrWhiteSpace(p.car))
.GroupBy(p => p.PersonID)
.Select(g => new Result
{
PersonID = g.Key,
Cars = g.Select(p => p.car).ToList()
})
.ToList();
Order groups or values
var results = persons
.GroupBy(p => p.PersonID)
.OrderBy(g => g.Key)
.Select(g => Result
{
PersonID = g.Key,
Cars = g.Select(p => p.car).OrderBy(car => car).ToList()
})
.ToList();
Common Mistakes
1. Forgetting to select the property you actually want
Broken code:
var results = persons
.GroupBy(p => p.PersonID)
.Select(g => new Result
{
PersonID = g.Key,
Cars = g.ToList()
});
Problem:
g.ToList()returns aList<Person>- but
Carsexpects aList<string>
Fix:
Cars = g.Select(x => x.car).ToList()
2. Confusing the group key with group items
Broken thinking:
g.Keyis the IDgis the collection of all matching items
Do not try to get car names from g.Key.
3. Forgetting ToList() when a List<string> is required
Broken code:
Cars = g.Select(x => x.car)
Comparisons
GroupBy vs related LINQ operations
| Concept | What it does | When to use it |
|---|---|---|
Select | Transforms each item | When you want one output per input item |
Where | Filters items | When you want to remove items that do not match a condition |
GroupBy | Buckets items by a key | When you want one output per group |
ToDictionary | Builds key-value lookup data | When keys must be unique in the final result |
Distinct | Removes duplicates | When you only need unique values, not grouped collections |
Query syntax vs method syntax
Cheat Sheet
// Group by key and collect values
var results = persons
.GroupBy(p => p.PersonID)
.Select(g => new Result
{
PersonID = g.Key,
Cars = g.Select(p => p.car).ToList()
})
.ToList();
Key ideas
GroupBy(p => p.PersonID)groups items byPersonIDg.Keygives the group keygcontains all items in that groupg.Select(p => p.car)extracts car namesToList()converts the sequence toList<string>
Query syntax version
var results = from p in persons
group p by p.PersonID into g
select new Result
{
PersonID = g.Key,
Cars = g.Select(x => x.car).ToList()
};
Useful variations
Distinct values
Cars = g.Select(x => x.car).Distinct().ToList()
FAQ
How do I get the list of values from each LINQ group?
Use Select on the group itself. For example, g.Select(x => x.car).ToList() extracts all car names from that group.
What does g.Key mean in LINQ GroupBy?
g.Key is the value used for grouping. In this case, it is the PersonID.
Can I group by one property and select another in LINQ?
Yes. You can group by PersonID and then select car, name, date, or any other property from the grouped items.
Should I use query syntax or method syntax for GroupBy?
Both are valid. Method syntax is more common in many C# codebases, but query syntax can be easier to read for some learners.
How do I remove duplicate cars inside each group?
Use Distinct() before ToList():
Cars = g.Select(x => x.car).Distinct().ToList()
Can GroupBy return a custom class?
Yes. After grouping, use to create instances of your own class, such as .
Mini Project
Description
Build a small C# console example that groups people by PersonID and prints the list of cars owned by each person. This demonstrates how to transform repeated records into grouped output that is easier to use in reports, APIs, or UI screens.
Goal
Create a grouped list where each person ID appears once and contains all associated car names.
Requirements
- Create a
Personclass withPersonIDandcar - Create a
Resultclass withPersonIDandList<string> Cars - Add sample data with repeated
PersonIDvalues - Use LINQ
GroupByto build the grouped result - Print each person ID and their cars to the console
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
C# Type Checking Explained: typeof vs GetType() vs is
Learn when to use typeof, GetType(), and is in C#. Understand exact type checks, inheritance, and safe type testing clearly.
C# Version Numbers Explained: C# vs .NET Framework and Why “C# 3.5” Is Incorrect
Learn the correct C# version numbers, how they map to .NET releases, and why terms like C# 3.5 are inaccurate and confusing.