What LINQ Is and When to Use It
LINQ is a unified querying model built into .NET that lets you filter, transform, join, and aggregate data using a consistent syntax across in-memory collections, databases, XML, JSON, and more. It provides two interchangeable forms: the SQL-like query syntax and the fluent method syntax. Both compile to the same underlying operations.
Use LINQ when you want clear, declarative code for tasks such as:
- Filtering and projecting data from lists, arrays, or
IEnumerable<T>sources - Joining related collections
- Sorting or grouping results
- Paging through data with
SkipandTake - Applying element selectors like
First,Single, orLast - Converting results into arrays, lists, dictionaries, or lookups
LINQ is not a replacement for algorithms that depend on manual indexing, mutation, or tight loops where performance overhead matters. Its strength is expressing data transformations concisely and predictably.
LINQ Cheat Sheet
Data assumptions
IEnumerable<Customer> customers;
IEnumerable<Order> orders;
Filtering
Query syntax
var col =
from o in orders
where o.CustomerID == 84
select o;
Method syntax
var col2 = orders.Where(o => o.CustomerID == 84);
Returning Anonymous Types
Query syntax
var col =
from o in orders
select new
{
OrderID = o.OrderID,
Cost = o.Cost
};
Method syntax
var col2 = orders.Select(o => new
{
OrderID = o.OrderID,
Cost = o.Cost
});
Ordering
Simple ascending
var col =
from o in orders
orderby o.Cost ascending
select o;
var col2 = orders.OrderBy(o => o.Cost);
Simple descending
var col3 =
from o in orders
orderby o.Cost descending
select o;
var col4 = orders.OrderByDescending(o => o.Cost);
Multiple keys
var col5 =
from o in orders
orderby o.CustomerID, o.Cost descending
select o;
var col6 = orders
.OrderBy(o => o.CustomerID)
.ThenByDescending(o => o.Cost);
Note on multiple orderby clauses
var col7 =
from o in orders
orderby o.Cost descending
orderby o.CustomerID
select o;
// The last orderby wins. The effective ordering is by CustomerID only.
Joining
Query syntax
var col =
from c in customers
join o in orders
on c.CustomerID equals o.CustomerID
select new
{
c.CustomerID,
c.Name,
o.OrderID,
o.Cost
};
Method syntax
var col2 = customers.Join(
orders,
c => c.CustomerID,
o => o.CustomerID,
(c, o) => new
{
c.CustomerID,
c.Name,
o.OrderID,
o.Cost
});
Grouping
Query syntax
var orderCounts =
from o in orders
group o by o.CustomerID into g
select new
{
CustomerID = g.Key,
TotalOrders = g.Count()
};
Method syntax
var orderCounts1 = orders
.GroupBy(o => o.CustomerID)
.Select(g => new
{
CustomerID = g.Key,
TotalOrders = g.Count()
});
Note
The grouping key type matches the expression you group by.
If o.CustomerID is an int, then g.Key is an int.
Paging with Skip and Take
Top N
// Top 3 orders for a specific customer
var top3 =
(from o in orders
where o.CustomerID == 84
select o).Take(3);
var top3b = orders
.Where(o => o.CustomerID == 84)
.Take(3);
Skip and Take
// Skip first 2, then take the next 2, ordered by Cost
var page =
(from o in orders
where o.CustomerID == 84
orderby o.Cost
select o).Skip(2).Take(2);
var page2 = orders
.Where(o => o.CustomerID == 84)
.OrderBy(o => o.Cost)
.Skip(2)
.Take(2);
Element Operators
Single, Last, First, ElementAt and their *OrDefault versions.
Single element
// Throws if zero or more than one match
var cust =
(from c in customers
where c.CustomerID == 84
select c).Single();
var cust1 = customers.Single(c => c.CustomerID == 84);
SingleOrDefault
// Returns null (reference type) or default(T) if no match
var cust2 =
(from c in customers
where c.CustomerID == 84
select c).SingleOrDefault();
var cust3 = customers.SingleOrDefault(c => c.CustomerID == 84);
DefaultIfEmpty with Single
// Returns a new Customer if no element matches
var cust4 =
(from c in customers
where c.CustomerID == 85
select c)
.DefaultIfEmpty(new Customer())
.Single();
var cust5 = customers
.Where(c => c.CustomerID == 85)
.DefaultIfEmpty(new Customer())
.Single();
First / Last
var lastOrder =
(from o in orders
where o.CustomerID == 84
orderby o.Cost
select o).Last();
var lastOrder2 = orders
.Where(o => o.CustomerID == 84)
.OrderBy(o => o.Cost)
.Last();
Example with value type default
// Returns 0 if there is no matching CustomerID
var i =
(from c in customers
where c.CustomerID == 85
select c.CustomerID).SingleOrDefault();
var j = customers
.Where(c => c.CustomerID == 85)
.Select(c => c.CustomerID)
.SingleOrDefault();
Behavior summary
-
Single,Last,First,ElementAtThrow exceptions if the source sequence is empty (or in the case ofSingle, if there is more than one matching element). -
SingleOrDefault,LastOrDefault,FirstOrDefault,ElementAtOrDefaultReturndefault(T)if the source sequence is empty.- For reference types and nullable value types,
default(T)isnull. - For non-nullable value types (like
int,bool), you get their default value (0,false, etc).
- For reference types and nullable value types,
Conversions
ToArray
string[] names =
(from c in customers
select c.Name).ToArray();
ToDictionary
Dictionary<int, Customer> byId =
customers.ToDictionary(c => c.CustomerID);
More complex example:
var customerOrdersWithMaxCost =
(from oc in
(from o in orders
join c in customers
on o.CustomerID equals c.CustomerID
select new { c.Name, o.Cost })
group oc by oc.Name into g
select g)
.ToDictionary(
g => g.Key,
g => g.Max(oc => oc.Cost));
ToList
List<Order> ordersOver10 =
(from o in orders
where o.Cost > 10
orderby o.Cost
select o).ToList();
ToLookup
ILookup<int, string> customerLookup =
customers.ToLookup(c => c.CustomerID, c => c.Name);