I figured out a very LINQy way to do it
bool isOrdered = ids.Skip(1).Concat(new List<int>() { int.MaxValue })
.Zip(ids, (y, x) => y >= x)
.All(z => z);
However, it is not very efficient or compact. Is there a better way?
I figured out a very LINQy way to do it
bool isOrdered = ids.Skip(1).Concat(new List<int>() { int.MaxValue })
.Zip(ids, (y, x) => y >= x)
.All(z => z);
However, it is not very efficient or compact. Is there a better way?
Aggregate
is a way to walk sequence and keep track of previous item(s)
(new int[]{1,2,3}).Aggregate(
new { IsSorted = true, Previous = int.MinValue },
(state, current) => new {
IsSorted = (state.IsSorted && current > state.Previous),
Previous = current})
.IsSorted
Unfortunately with Aggregate
there is no way to stop early unlike with .Zip()
solution where you can stop early with .All
as you have in your sample.
var isOrdered = ids.Zip(ids.Skip(1), (curr, next) => curr <= next).All(x => x);
If you're willing to be a bit more constrained and assume that rather than IEnumerable<int>
you had an IList<int>
you could do this, which allows you to quit early:
ids.Skip(1).Select( (val,ix) => val >= ids.ElementAt(ix-1) ).All( x => x);
It would function for any enumerable but it would be O(n^2) in the case where ids is not an IList. If you need this to work for any IEnumerable than @AlexeiLevenkov's solution is the best one.