Change (revised):. This answer causes a problem with a query being executed twice, which in my opinion is a key problem. The following shows why:
Making Any() smarter is something that only Linq, IMO performers can do ... Or it would be a dirty adventure using reflection.
Using the class as shown below, you can cache the output of the original enumeration and enumerate it twice:
public class CachedEnumerable<T> { public CachedEnumerable(IEnumerable<T> enumerable) { _source = enumerable.GetEnumerator(); } public IEnumerable<T> Enumerate() { int itemIndex = 0; while (true) { if (itemIndex < _cache.Count) { yield return _cache[itemIndex]; itemIndex++; continue; } if (!_source.MoveNext()) yield break; var current = _source.Current; _cache.Add(current); yield return current; itemIndex++; } } private List<T> _cache = new List<T>(); private IEnumerator<T> _source; }
This way you keep the lazy aspect of LINQ, keep it readable and universal. This will be slower than directly using IEnumerator<> . There are many possibilities for expanding and optimizing this class, such as the policy of abandoning old elements, getting rid of coroutines, etc. But this is not the case, I think.
Oh, and the class is not thread safe as it is now. This was not asked, but I can imagine how people are trying. I think that this could easily be added if the source enumerated does not have downstream proximity.
Why is this optimal?
Consider two options: an enumeration may contain elements or not.
- If it contains elements, this approach is optimal, since the request is run only once.
- If there are no elements in it, you will be tempted to exclude OrderBy and select a part of your queries, because they add no matter. But .. if after the
Where() clause there are null elements, for sorting the null elements will cost zero time (well, almost). The same goes for the Select() clause.
What if it is not fast enough yet? In this case, my strategy would be to bypass Linq. Now, I really love linq, but this elegance comes at a price. Therefore, for every 100 times you use Linq, there will usually be one or two calculations that are important to perform very quickly, which I write with the good old for loops and lists. Part of mastering technology is recognizing where it does not fit. Linq is no exception to this rule.
user180326
source share