1

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?

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179

3 Answers3

2

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.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
2
    var isOrdered = ids.Zip(ids.Skip(1), (curr, next) => curr <= next).All(x => x);
Pedro Perez
  • 842
  • 6
  • 23
0

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.

PMV
  • 2,058
  • 1
  • 10
  • 15