How intelligent is Linq with IOrderedEnumerable and Where

380 Views Asked by At

so let's say I have an IEnumerable dates and I want to get the dates within a range.

Is Linq and IOrderedEnumerable intelligent enough to realize the ability to choose faster algorithms given that the dates are now ordered.

So consider this:

IOrderedEnumerable<ObjectWith2DateTimes> orderedDates = dates.OrderBy(x => new Tuple(x.datetime1,x.datetime2));

...
this is called a bunch
...
    DateTime afterDateTime = (some datetime)
    DateTime beforeDateTime = (other datetime)
    yield return orderedDates.Where(x => x.datetime1 >= afterDateTime && x.datetime2 <= beforeDateTime)

If isn't smart with this implementation, is there some other implementation that would make it smart?

4

There are 4 best solutions below

3
On BEST ANSWER

No it's not smart enough to do that. Enumerable.Where<TSource> takes a Func<TSource, bool>, not an Expression<Func<TSource, bool>> like Queryable.Where<TSource>. So you could do it with an IQueryable, but you'd need a query provider that can do that. It's probably not worth the trouble.

However, something like this should do:

orderedDates
    .SkipWhile(x => x.datetime1 < afterDateTime)
    .TakeWhile(x => x.datetime2 > beforeDateTime)
0
On

No; the Where operator has no idea what your predicate does; it just knows to invoke a delegate that tells it whether to include an item in the result set. It would be possible for a query provider to do this with IOrderedQueryable, as the query provider would be able to analyze the expression tree. I do not know if any query providers actually do that kind of analysis.

0
On

No. Where extension method does simple, linear search over all items in your collection and returns element if it follows your predicate. You can think of it as:

foreach(var item in source)
    if(predicate(item))
        yield return item;
0
On

LINQ-to-objects works with delegates and treats them as blackboxes. So it does not know that your where condition has any relation to the earlier ordering operation. So it does not perform this optimization.

It's even worse than that, the sorting will be done each time you evaluate the query, even if it's shared. You need to materialize it with ToArray or ToList. Then you can use the built-in binary search function to speed this up.