Reputation: 97
I'm solving a problem, and I understood that these codes work in different ways, but I can't understand why the second one isn't correct and what's the difference.
public Person GetOldestMember()
{
Person oldestPerson = people.OrderByDescending(x => x.Age).FirstOrDefault();
return oldestPerson;
}
.
public Person GetOldestMember()
{
Person oldestPerson = new Person(-1); //this is a constructor with parameter age
foreach (Person person in people)
{
if (person.Age > oldestPerson.Age)
{
oldestPerson = person;
}
}
return oldestPerson;
}
Upvotes: 0
Views: 114
Reputation: 1062685
OrderBy
, for example) can be really very expensiveIF WE ASSUME THAT THIS IS IN-MEMORY DATA (LINQ-Objects) - something like IEnumerable<Person>
, List<Person>
, Person[]
, etc:
Note that sorting is a relatively expensive operation, and when using LINQ that also usually means creating a copy of the data (so as not to change the source). There are external extension methods available that do this more efficiently within the LINQ concept, i.e.
Person oldestPerson = people.MaxBy(x => x.Age);
Again, not quite as efficient as the loop, but tons more efficient than OrderByDescending
+FirstOrDefault
... just watch out how this behaves for empty inputs (it might throw rather than returning null
).
However, as Dzyann observes in the comments: people
here could be an IQueryable<Person>
- something like a DbSet<Person>
from EF or LINQ-to-SQL (etc), in which case everything changes: now we're talking about queries that get pushed down to an external resource, in which case the OrderByDescending
+ FirstOrDefault
could become SQL like:
SELECT TOP 1 *
FROM People
ORDER BY Age DESC
and we've become a hero. If we did that via foreach
over an IQueryable<Person>
, we would have issued:
SELECT *
FROM People
then fetched everything over the network as we iterate locally to see which is oldest.
Upvotes: 6
Reputation: 17002
One of the things about LINQ queries that isn't immediately obvious is that they tend to "fail fast". That is, they exit the loop as soon as the specified criteria is met, rather than iterating over the entire sequence.
For example, FirstOrDefault()
gets the first item from the sequence and exits immediately, if there are any items in the sequence. If there aren't any, it immediately returns null. It does not iterate over the sequence.
Your for
loop, however, iterates over each element in the sequence. If the sequence is very large, this can be time consuming. Further, if your exit condition is wrong or missing altogether, you may return the wrong element (although that can happen in LINQ expressions as well).
LINQ expressions are very efficient, retrieving only the data that is necessary to fulfill the request as fast as possible. It's unlikely you'll write a more efficient for
loop (though not impossible).
Upvotes: -2