What is the difference between `Where().Select()` and `Select().Where()`?
Quick Answer
Both produce the same elements, but order affects work done. `Where().Select()` filters first, so the (often more expensive) projection runs only on matching elements — usually more efficient. `Select().Where()` projects every element first, then filters, doing extra transformation work. Filter as early as possible; the exception is when the projection is needed to evaluate the predicate.
Detailed Answer
Both produce the same final result, but they differ in performance and efficiency.
Where().Select() - Filter First, Then Transform
- Better Performance: Filters data before transformation
- Fewer operations: Only transforms elements that pass the filter
- Recommended approach in most cases
Select().Where() - Transform First, Then Filter
- Worse Performance: Transforms all elements before filtering
- More operations: Wastes resources on elements that will be filtered out
- Useful only when the transformation is needed for filtering logic
var numbers = Enumerable.Range(1, 1000);
// WHERE THEN SELECT (Recommended)
var result1 = numbers
.Where(n => n > 500) // 1. Filter: 500 elements remain
.Select(n => n * n); // 2. Transform: 500 operations
// SELECT THEN WHERE (Less Efficient)
var result2 = numbers
.Select(n => n * n) // 1. Transform: 1000 operations
.Where(n => n > 250000); // 2. Filter: 500 elements remain
// Both produce the same result, but result1 performs half the transformations!
Performance Comparison:
// Example with complex objects
var users = GetUsers(); // 10,000 users
// EFFICIENT: Filter first
var result1 = users
.Where(u => u.Age > 18) // Filter 10,000 -> 6,000
.Select(u => new UserDto // Transform 6,000 objects
{
FullName = u.FirstName + " " + u.LastName,
Email = u.Email
});
// INEFFICIENT: Select first
var result2 = users
.Select(u => new UserDto // Transform 10,000 objects
{
FullName = u.FirstName + " " + u.LastName,
Email = u.Email
})
.Where(dto => CalculateAge(dto) > 18); // Filter 10,000 -> 6,000
// result1 creates 6,000 DTO objects
// result2 creates 10,000 DTO objects (4,000 wasted)
When to Use Each:
Use Where().Select() when:
- Filter condition uses original object properties
- You want to minimize transformations
- Performance matters (almost always)
var activeUsers = users
.Where(u => u.IsActive)
.Select(u => u.Name);
Use Select().Where() when:
- Filter condition requires the transformed data
- The transformation is necessary for filtering logic
var validEmails = users
.Select(u => u.Email.Trim().ToLower())
.Where(email => email.Contains("@company.com"));
// Or even better, combine them:
var validEmails = users
.Where(u => u.Email != null)
.Select(u => u.Email.Trim().ToLower())
.Where(email => email.Contains("@company.com"));
Rule of Thumb: Filter as early as possible in the LINQ chain to reduce the number of elements processed by subsequent operations.
// BEST: Filter -> Filter -> Select
var result = items
.Where(i => i.IsActive) // First filter
.Where(i => i.Price > 100) // Second filter
.Select(i => i.Name); // Final transformation
// WORST: Select -> Where -> Where
var result = items
.Select(i => new { i.Name, i.Price, i.IsActive })
.Where(i => i.IsActive)
.Where(i => i.Price > 100);