tags:

views:

87

answers:

4

I have;

var maxVal = l.TakeWhile(x=>x < val).Where(x=>Matches(x)).Max();

How much space does this need ? Does linq build up a list of the above Where() condition, or is Max() just iterating through the IEnumerable keeping track of what is the current Max() ?

And where can I find more info about this, besides asking on SO f

+7  A: 

I have verified with Reflector that each of Enumerable.TakeWhile, Enumerable.Where and Enumerable.Max run in constant space. Consequently, this entire query should run in constant space. Not surprising, considering TakeWhile and Where are speced to use deferred execution + streaming. Max does not use deferred execution, but only needs to store 'max so far' and the enumerator on the source enumerable.

Ani
It makes sense that Max doesn't use deferred execution, as it returns a T not a IEnumerable<T>.A different way of looking at it, is that none of them really do deferred execution; they all immediately return an object that will behave in different ways when enumerated through. The result of Max() however, isn't enumerated through. While this isn't the best way of thinking of things most of the time, it can help when trying to remember what is and isn't deferred.
Jon Hanna
A: 

According to the Reflector Max() method iterates through the enumerable.

And where can I find more info about this, besides asking on SO f

You can use Reflector to look at the implementation of any .NET assembly.

Andrew Bezzub
A: 

Reflector is your friend.

In particular, you can take a look at Linq to Objects extension methods in the Enumerable class in System.Linq.

The above are using iterations, so they use the whatever space the enumerators takes up - usually O(1). Max() is O(1) space.

However, keep in mind that nothing stops a developer from writing an enumerator that takes up more than constant space. E.g. traversing a tree may require O(log n) space. This is the case e.g. for SortedDictionary<K,V> and SortedSet<K,V>.

So it partially depends on what l is in your code.

andras
A: 

The only thing offered by Enumerable that I've found doesn't run in constant space is ToList(), for obvious reasons.

With some enumerations, this is inefficient, in that you already have a space complexity above constant (typically O(n) as you are storing the items) and that the collection in question offers a mechanism with lower time complexity. If you are creating such a collection yourself it makes sense to offer your own versions of the extensions offered by Enumerable. For example, if you have a collection that is inherently sorted you should be able to offer Min() and Max() in better than O(n) complexity (whether it is O(1), O(ln) or something else would depend on what way that sorting was kept). Since instance methods override extension methods (when called on an expression of the object type rather than the instance type) then with no difference to the coder using your object, you will offer better efficiency.

Jon Hanna
To my knowledge, none of ToArray(), ToList(), ToDictionary(), ToLookup(), OrderBy(), OrderByDescending(), GroupBy(), Distinct() run in constant space. There may be more.You are right about the efficiency bit though; I wouldn't call SortedList.Values.Max(), though who knows what optimizations MS will put in, in the future.
Ani
Gah! Yes, those you mention are all above constant space, they'd just slipped my mind when commenting. One optimisation already put in is that Count() does a check for whether the enumeration is an ICollection and if it is, returns the value of its Count property.
Jon Hanna