8

I'm having trouble writing a method that returns true if the elements of an array (numbers) are in sorted order, ascending or descending, and false, if they are not in any sorted order. I can return a correct boolean value if the array is ascending but i do not know how to check for descending order as well in the same method. I currently have:

public static bool IsArraySorted(int[] numbers)
{
    for (int i = 1; i < numbers.Length; i++)
    {
        if (numbers[i - 1] > numbers[i])
            return false;
    }

    return true;
}

Anyone able to offer help on how to check for a sorted descending array as well? Cheers!

3
  • If there are two continguus values with the same number which is the desired behavior ? Commented Jun 15, 2015 at 11:49
  • Using return exits your function, while you presumably want to loop on the whole collection before returning anything... Commented Jun 15, 2015 at 11:55
  • @Bartdude I think that's by design - if you've already discovered that it's not sorted, there's no need to check the rest of the array :-) Commented Jun 15, 2015 at 13:31

8 Answers 8

9

It should be something like:

public static bool IsArraySorted(int[] numbers)
{
    bool? ascending = null;

    for (int i = 1; i < numbers.Length; i++)
    {
        if (numbers[i - 1] != numbers[i])
        {
            bool ascending2 = numbers[i - 1] < numbers[i];

            if (ascending == null)
            {
                ascending = ascending2;
            }
            else if (ascending.Value != ascending2)
            {
                return false;
            }
        }
    }

    return true;
}

Note the use of the ascending variable to save the "direction" of the array. It is initialized the first time two elements that are different are found.

Note that if you want, you can even return the "direction" of the array:

public static bool IsArraySorted(int[] numbers, out bool isAscending)
{
    isAscending = true;
    bool? ascending = null;

and inside the if (ascending == null)

if (ascending == null)
{
    ascending = ascending2;
    isAscending = ascending2;
}

This is a generic version based on IEnumerable<TSource>:

public static bool IsSorted<TSource>(IEnumerable<TSource> source, out bool isAscending, Comparer<TSource> comparer = null)
{
    isAscending = true;

    if (comparer == null)
    {
        comparer = Comparer<TSource>.Default;
    }

    bool first = true;
    TSource previous = default(TSource);

    bool? ascending = null;

    foreach (TSource current in source)
    {
        if (!first)
        {
            int cmp = comparer.Compare(previous, current);

            if (cmp != 0)
            {
                bool ascending2 = cmp < 0;

                if (ascending == null)
                {
                    ascending = ascending2;
                    isAscending = ascending2;
                }
                else if (ascending.Value != ascending2)
                {
                    return false;
                }
            }
        }

        first = false;
        previous = current;
    }

    return true;
}

Note the use of bool first/TSource previous to handle the i - 1 (and the fact that the for cycle was able to "skip" the first element)

Sign up to request clarification or add additional context in comments.

6 Comments

Can I only use (numbers.Length/2) insted of going through complete list ?
@Amit ???? { 1, 2, 3, -5 } How would you catch the out-of-order -5 if you don't check the last value?
@xanatos, You'll get an OutOfRangeException if the array passed in has a length of 0 or 1. You'll want some argument checks at the top of the method.
@WyattEarp No... because there is no code accessing the array before the for (), and the for() will block for arrays of length <= 1, int i = 1; i < numbers.Length
@xanatos, Ah, my mistake. Though, you would get a NullReferenceException if the array were null.
|
3

Using Linq -

public static bool IsArraySorted(int[] numbers)
{
    var orderedAsc = numbers.OrderBy(a => a);
    var orderedDes = numbers.OrderByDescending(a => a);

    bool isSorted = numbers.SequenceEqual(orderedAsc) ||
                    numbers.SequenceEqual(orderedDes);
    return isSorted;
}

Comments

2

This uses one loop to test both cases:

public static bool IsSorted<T>(IEnumerable<T> items, Comparer<T> comparer = null)
{
    if (items == null) throw new ArgumentNullException("items");
    if (!items.Skip(1).Any()) return true;  // only one item

    if (comparer == null) comparer = Comparer<T>.Default;
    bool ascendingOrder = true; bool descendingOrder = true;

    T last = items.First();
    foreach (T current in items.Skip(1))
    {
        int diff = comparer.Compare(last, current);
        if (diff > 0)
        {
            ascendingOrder = false;
        }
        if (diff < 0)
        {
            descendingOrder = false;
        }
        last = current;
        if(!ascendingOrder && !descendingOrder) return false;
    }
    return (ascendingOrder || descendingOrder);
}

usage:

int[] ints = { 1, 2, 3, 4, 5, 6 };
bool isOrderedAsc = IsSorted(ints); // true
bool isOrderedDesc = IsSorted(ints.Reverse()); //true

If you make it an extension method you can use it with any type:

bool ordered = new[]{"A", "B", "C"}.IsSorted();

6 Comments

I do think it is <strike>an abomination</strike> a very bad bad thing to enumerate twice the IEnumerable<>... (First/Skip)
@xanatos: Why? I don't enumerate it twice. If it's a collection it's just taking the first item whereas Skip(1) is the enumeration that omits the first. What is the abomination?
Try doing it to a IQueryable<>... The query is resolved twice (technically two different queries are executed... one that has a TOP 1 and another that emulates the Skip(1))
@xanatos: Why do you want to use this method for a database query? You could, but it is not meant for this purpose. Your method on the other hand is not reusable at all. He could change the signature to accept only IList<T> but i wouldn't.
Is there something in your code/in your explanation that says explicitly "I'll enumerate twice, don't use me if you are using slow IEnumerable<>"? Warning stickers are important.
|
1
public static boolean checkSortedness(final int[] data) 
{
    for (int i = 1; i < data.length; i++) 
    {
        if (data[i-1] > data[i]) {
            return false;
        }
    }
    return true;
}

2 Comments

this validates only a ascending sorted list but fails at a descending sorted list
final is Java, not C#
1

Where is my answer? I wrote it about an hour ago:

public enum SortType
{
     unsorted   = 0,
     ascending  = 1,
     descending = 2
}

public static SortType IsArraySorted(int[] numbers)
{
    bool ascSorted = true;
    bool descSorted = true;

    List<int> asc = new List<int>(numbers);            

    asc.Sort();

    for (int i = 0; i < asc.Count; i++)
    {
        if (numbers[i] != asc[i]) ascSorted = false;
        if (numbers[asc.Count - 1 - i] != asc[i]) descSorted = false;
    }

    return ascSorted ? SortType.ascending : (descSorted? SortType.descending : SortType.unsorted);
}

Example:

enter image description here

Comments

0

It looks more like an academic assignment than a practical question. I guess it does not hurt to return to basics once in a while:

public static bool IsSortedAscOrDesc(int[] arr)
{
    int last = arr.Length - 1;
    if (last < 1) return true;

    bool isSortedAsc = true;
    bool isSortedDesc = true;

    int i = 0;
    while (i < last && (isSortedAsc || isSortedDesc)) 
    {
        isSortedAsc &= (arr[i] <= arr[i + 1]);
        isSortedDesc &= (arr[i] >= arr[i + 1]);
        i++;
    }

    return isSortedAsc || isSortedDesc;
}

Comments

0

An array with 2 (or less) elements is sorted,
{0,0} is sorted asc & desc, {0,1} asc, {1,0} desc, {1,1} asc & desc.
It is possible to use one loop, but it seems faster to separate cases. For an array with more than 2 elements,
if the first element is less than the last element, check: a[i] <= a[i + 1].
Below I use "ai <= (ai = a[i])", compare the old value of ai with the new value of ai, each element is read once.

using System;
class Program
{
    static void Main()
    {
        int i = 512; int[] a = new int[i--]; while (i > 0) a[i] = i--; //a[511] = 1;
        Console.WriteLine(isSorted0(a));
        var w = System.Diagnostics.Stopwatch.StartNew();
        for (i = 1000000; i > 0; i--) isSorted0(a);
        Console.Write(w.ElapsedMilliseconds); Console.Read();
    }

    static bool isSorted0(int[] a)  // 267 ms
    {
        if (a.Length < 3) return true; int j = a.Length - 1;
        return a[0] < a[j] ? incr(a) : a[0] > a[j] ? decr(a) : same(a);
    }
    static bool incr(int[] a)
    {
        int ai = a[0], i = 1, j = a.Length;
        while (i < j && ai <= (ai = a[i])) i++; return i == j;
    }
    static bool decr(int[] a)
    {
        int ai = a[0], i = 1, j = a.Length;
        while (i < j && ai >= (ai = a[i])) i++; return i == j;
    }
    static bool same(int[] a)
    {
        int ai = a[0], i = 1, j = a.Length - 1;
        while (i < j && ai == a[i]) i++; return i == j;
    }

    static bool isSorted1(int[] numbers)  // 912 ms  accepted answer
    {
        bool? ascending = null;
        for (int i = 1; i < numbers.Length; i++)
            if (numbers[i - 1] != numbers[i])
            {
                bool ascending2 = numbers[i - 1] < numbers[i];
                if (ascending == null) ascending = ascending2;
                else if (ascending.Value != ascending2) return false;
            }
        return true;
    }
}

A short version.

    static bool isSorted(int[] a)
    {
        if (a.Length < 3) return true; int i = a.Length - 1, ai = a[i--];
        if (ai > a[0]) while (i >= 0 && ai >= (ai = a[i])) i--;
        else if (ai < a[0]) while (i >= 0 && ai <= (ai = a[i])) i--;
        else while (i >= 0 && ai == a[i]) i--; return i < 0;
    }

Comments

0

I have written this method to check is an array sorted in ascending order.I would be grateful for your reviews.


        static void Main(string[] args)
        {
            int[] arrayToCheck = { 1, 1, 3, 5 ,2, 7};
            
            Console.WriteLine(IsSorted(arrayToCheck));
            
        }

In the first step I setted up "for loop" to check every single array integer is less than integer with index - 1. And then I created Array of booleans which stored all of these conditions (true/false).

 static bool IsSorted(int[] array)
        {
            bool[] checkAscending = new bool[array.Length - 1];

            for (int i = 1; i < array.Length; i++)
            {
                checkAscending[i - 1] = array[i] >= array[i - 1];
                
            }

In the second step in order to assign value of 1 to true and 0 to false conditionI setted up "for loop" nesting if and else condition.

            int[] trueToOne = new int[checkAscending.Length];
            
            for (int i = 0; i < checkAscending.Length; i++)
            {
                if (checkAscending[i] == true)
                    trueToOne[i] = 1;
                else if (checkAscending[i] == false)
                    trueToOne[i] = 0;
            }

In the last step I had to create new method "Add" which takes array of integers as a parameter and adding every single array character. If result of addition is equal to array trueToOne length that means all condition are true and Array of integers is sorted.



            int result = Add(trueToOne);

            if (result == trueToOne.Length)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

And ADD METHOD:


        public static int Add(int[] array)
        {
            int[] sum = new int[array.Length];


            for (int i = 1; i < array.Length; i++)
            {
                sum[0] = array[0];
                sum[i] = array[i] + sum[i - 1];
            }

            return sum[sum.Length - 1];
        }

    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.