GroupBy in LINQ — Complete Guide
GroupBy in LINQ — Complete Guide: free step-by-step lesson with examples, common mistakes, and interview tips — part of LINQ Tutorial on Toolliyo Academy.
On this page
LINQ Tutorial · Lesson 31 of 100
GroupBy
Beginner ✓ → Intermediate → Advanced → Professional
Intermediate · 2 — Queries & joins · ~14 min read · Module 4: Grouping & Joining · ShopNest.Analytics
Introduction
You know LINQ basics now. Here we use GroupBy in real app situations — filters, reports, and search. Still plain language, just a bit more depth. GroupBy splits a list into buckets by a key — all orders in "Mumbai", all in "Delhi". After grouping, you can Count, Sum, or Average inside each bucket. Sales dashboards ask "revenue per region" or "orders per customer". GroupBy answers that in a few lines instead of a Dictionary and manual loops.
GroupBy is on almost every analytics interview paper. Practice with a 5-row sample list until you can predict the output before running.
When will you use this?
Use grouping and joins when a screen shows summaries — sales by city, orders per customer.
- Sales dashboards group orders by region. HR reports group employees by department.
- Join links orders to customers — the same pattern in billing, CRM, and inventory apps.
Real-world: Flipkart-style marketplace
Real product: Flipkart-style marketplace (E-commerce). sellers and shoppers rely on product search and order reports every day. On this product, developers use GroupBy in LINQ to show sales total per region or orders per customer. Without it, the team would write longer loops, ship slower features, or pull too much data from SQL Server. The example below is simplified on purpose — production code adds error handling, logging, and tests around the same LINQ pattern.
Production-style code
// ShopNest sales dashboard — revenue by region (EF Core)
public async Task<List<RegionSalesDto>> GetRegionSalesAsync(DateTime from, CancellationToken ct)
{
return await _context.Orders
.AsNoTracking()
.Where(o => o.OrderDate >= from)
.GroupBy(o => o.Region.Name)
.Select(g => new RegionSalesDto
{
Region = g.Key,
OrderCount = g.Count(),
Revenue = g.Sum(o => o.GrandTotal)
})
.OrderByDescending(x => x.Revenue)
.ToListAsync(ct);
}
What happens in production: In Flipkart-style marketplace, getting GroupBy in LINQ right means sellers and shoppers see correct product search and order reports quickly. That is the difference between a tutorial snippet and software people trust with money and operations data.
Lesson example (start here)
Copy this smaller example first. Once it works, compare it with the real-world code above.
var orders = new List<Order>
{
new Order { Id = 1, Region = "North", Total = 1200 },
new Order { Id = 2, Region = "South", Total = 800 },
new Order { Id = 3, Region = "North", Total = 500 }
};
var byRegion = orders
.GroupBy(o => o.Region)
.Select(g => new
{
Region = g.Key,
OrderCount = g.Count(),
Revenue = g.Sum(o => o.Total)
});
foreach (var row in byRegion)
Console.WriteLine($"{row.Region}: {row.OrderCount} orders, ₹{row.Revenue}");
Line-by-line walkthrough
| Code | What it means |
|---|---|
var orders = new List<Order> | Part of the GroupBy example — read it together with the lines before and after. |
{ | Part of the GroupBy example — read it together with the lines before and after. |
new Order { Id = 1, Region = "North", Total = 1200 }, | Part of the GroupBy example — read it together with the lines before and after. |
new Order { Id = 2, Region = "South", Total = 800 }, | Part of the GroupBy example — read it together with the lines before and after. |
new Order { Id = 3, Region = "North", Total = 500 } | Part of the GroupBy example — read it together with the lines before and after. |
}; | Closes a block started by { or ( above. |
var byRegion = orders | Part of the GroupBy example — read it together with the lines before and after. |
.GroupBy(o => o.Region) | Lambda expression — a short function, e.g. p => p.Price > 100 means "price greater than 100". |
.Select(g => new | Lambda expression — a short function, e.g. p => p.Price > 100 means "price greater than 100". |
{ | Part of the GroupBy example — read it together with the lines before and after. |
Region = g.Key, | Part of the GroupBy example — read it together with the lines before and after. |
OrderCount = g.Count(), | Terminal operator — runs the query and returns a number or true/false. |
Revenue = g.Sum(o => o.Total) | Lambda expression — a short function, e.g. p => p.Price > 100 means "price greater than 100". |
}); | Closes a block started by { or ( above. |
How it works (big picture)
- GroupBy(o => o.Region) creates groups keyed by region name.
- g.Key is that key.
- g itself is IEnumerable of orders in the group — you call Count and Sum on it.
- With EF Core, this becomes SQL GROUP BY.
Do this on your computer
- Create the sample orders list above in a console app.
- Run GroupBy + Select and print each group.
- Add a third order in a new region and confirm a new group appears.
- In a later lesson, run the EF Core version and read the SQL GROUP BY in logs.
- Read the real-world section and name which part of the app uses this topic.
- Run the example in a console app or LINQPad and confirm the output.
- Change one filter or sort in the example and predict the result before you run it.
Experiments — try changing this
- Change a filter value (price, date, name) and run again — see how results change.
- Remove one operator from the chain, run, and read the error or different output.
- In EF Core, enable SQL logging and see what SQL GroupBy generates.
Remember
GroupBy creates buckets by a key. Use Count, Sum, Average inside Select after grouping. EF Core translates GroupBy to SQL GROUP BY when used on IQueryable.
Common questions
GroupBy vs SQL GROUP BY?
Same idea — LINQ GroupBy on IQueryable becomes SQL GROUP BY.
Can I group by two fields?
Yes: .GroupBy(x => new { x.Year, x.Month }) or chain logic in the key selector.
Sign in to ask a question or upvote helpful answers.
No questions yet — be the first to ask!