-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
The fact of something being ordered can have implications for subsequent operations.
The ordering Linq methods (OrderBy
, ThenBy
, etc.) operate first in O(1) time and space to make a promise of a subsequent O(n log n) sort in O(n) space. In many case though the following operation does not need all of the promised operation.
.OrderBy(λ).First()
, .OrderBy(λ).First(λ)
, and so on request that a sequence be sorted (O(n log n) time/O(n) space) and then the first element taken (O(1) time and space) which is in total an O(n log n) time/O(n) space operation. However, it is reducible to the O(n) time/O(1) space operation of identifying just the item in question which can be done in O(n) time and O(1) space.
As First
, Last
and their variants are particularly common with ordered sequences (in some cases not having any meaning without an order), I think this would be a worth-while optimisation.
There are other optimisations available, such as all aggregate operations (Sum
etc.) could be moved from O(n log n) time to O(n) time simply by extracting the source and ignoring the ordering, this may not be as common a case as to make it worthwhile. One could argue that the user should have not put the ordering in there in the first place, and while the cost of checking for an ordered source is slightly, it's not worth paying it on all aggregate operations to benefit a flawed case.
Reverse
is somewhere in the middle. It's reasonable to expect someone might construct an ordered sequence and then Reverse
in some cases. It's got subtleties (one cannot simply reverse all OrderBy
to OrderByDescending
and vice-versa because OrderBy
is documented as performing stable ordering in linq-2-objects and therefore reversed must have reverse source ordering on equivalent items) but wouldn't be hard, but it's less clear whether the pay off would be worth it.
In the more useful cases of First
etc. there is a fly in the ointment in that this would affect the number of times both key selectors for ordering and predicates for First
etc. were called. As per #14842 this means side effects on Func
s would be affected, though perhaps in a way that was less predictable to the user than with that issue anyway.
As such, changing the behaviour of First
in this case would require either a decision in favour of the change that issue would allow for, or a decision that this case was less harmed by such changing side-effects.
In summary. I propose that OrderBy(…).First(…)
and its cousins be optimised, and the trade-offs of optimising OrderBy(…).Reverse()
be considered.