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
  • 96,782
  • 12
  • 124
  • 169

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
  • 96,782
  • 12
  • 124
  • 169
2
    var isOrdered = ids.Zip(ids.Skip(1), (curr, next) => curr <= next).All(x => x);
Pedro Perez
  • 792
  • 8
  • 20
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,038
  • 1
  • 9
  • 15