Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Native C# support for checking if an IEnumerable is sorted?

Is there any LINQ support for checking if an IEnumerable<T> is sorted? I have an enumerable that I want to verify is sorted in non-descending order, but I can't seem to find native support for it in C#.

I've written my own extension method using IComparables<T>:

public static bool IsSorted<T>(this IEnumerable<T> collection) where T : IComparable<T>
{
   Contract.Requires(collection != null);

   using (var enumerator = collection.GetEnumerator())
   {
      if (enumerator.MoveNext())
      {
         var previous = enumerator.Current;

         while (enumerator.MoveNext())
         {
            var current = enumerator.Current;

            if (previous.CompareTo(current) > 0)
               return false;

            previous = current;
         }
      }
   }

   return true;
}

And one using an IComparer<T> object:

public static bool IsSorted<T>(this IEnumerable<T> collection, IComparer<T> comparer)
{
   Contract.Requires(collection != null);

   using (var enumerator = collection.GetEnumerator())
   {
      if (enumerator.MoveNext())
      {
          var previous = enumerator.Current;

         while (enumerator.MoveNext())
         {
            var current = enumerator.Current;

            if (comparer.Compare(previous, current) > 0)
                return false;

            previous = current;
         }
      }
   }

   return true;
}
like image 989
Mikkel R. Lund Avatar asked Nov 05 '13 09:11

Mikkel R. Lund


Video Answer


2 Answers

You can check if collection is IOrderedEnumerable but that will work only if ordering is the last operation which was applied to sequence. So, basically you need to check all sequence manually.

Also keep in mind, that if sequence is IOrderedEnumerable you really can't say which condition was used to sort sequence.


Here is generic method which you can use to check if sequence is sorted in ascending order by field you want to check:

public static bool IsOrdered<T, TKey>(
    this IEnumerable<T> source, Func<T, TKey> keySelector)
{
    if (source == null)
        throw new ArgumentNullException("source");

    var comparer = Comparer<TKey>.Default;
    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
            return true;

        TKey current = keySelector(iterator.Current);

        while (iterator.MoveNext())
        {
            TKey next = keySelector(iterator.Current);
            if (comparer.Compare(current, next) > 0)
                return false;

            current = next;
        }
    }

    return true;
}

Usage:

string[] source = { "a", "ab", "c" };
bool isOrdered = source.IsOrdered(s => s.Length);

You can create similar IsOrderedDescending method - just change checking comparison result to comparer.Compare(current, next) < 0.

like image 65
Sergey Berezovskiy Avatar answered Nov 15 '22 04:11

Sergey Berezovskiy


There is no such built-in support.

Obviously if your IEnumerable<T> also implements IOrderedEnumerable<T> then you don't need to do an additional check, otherwise you'd have to implement an extension method like you did.

You might want to add a direction parameter or change its name to IsSortedAscending<T>, by the way. Also, there might be different properties in your T to sort on, so it would have to be obvious to you in some way what "sorted" means.

like image 33
Roy Dictus Avatar answered Nov 15 '22 04:11

Roy Dictus