How to determine if a List is sorted in Java?

JavaGenericsSortingWildcard

Java Problem Overview


I would like a method that takes a List<T> where T implements Comparable and returns true or false depending on whether the list is sorted or not.

What is the best way to implement this in Java? It's obvious that generics and wildcards are meant to be able to handle such things easily, but I'm getting all tangled up.

It would also be nice to have an analogous method to check if the list is in reverse order.

Java Solutions


Solution 1 - Java

Guava provides this functionality through its Comparators class.

boolean sorted = Comparators.isInOrder(list, comparator);

There's also the Ordering class, though this is mostly obsolete. An Ordering is a Comparator++. In this case, if you have a list of some type that implements Comparable, you could write:

boolean sorted = Ordering.natural().isOrdered(list);

This works for any Iterable, not just List, and you can handle nulls easily by specifying whether they should come before or after any other non-null elements:

Ordering.natural().nullsLast().isOrdered(list);

Also, since you mentioned that you'd like to be able to check for reverse order as well as normal, that would be done as:

Ordering.natural().reverse().isOrdered(list);

Solution 2 - Java

Stream

If you are using Java 8 or later, streams may be able to help.

list.stream().sorted().collect(Collectors.toList()).equals(list);

More briefly, in Java 16+, using Stream#toList.

list.stream().sorted().toList().equals(list);

This code will sort the list out of place and collect its elements in another list, which is then compared to the initial list. The comparison will be successful, if both lists contain the same elements in equal positions.

Note that this method will have worse space and time complexity than other approaches because it will have to sort the list out of place, so it should not be used for very large lists. But it is the easiest to use because it is a single expression and does not involve 3rd party libraries.

Solution 3 - Java

Here's a generic method that will do the trick:

public static <T extends Comparable<? super T>>
        boolean isSorted(Iterable<T> iterable) {
    Iterator<T> iter = iterable.iterator();
    if (!iter.hasNext()) {
        return true;
    }
    T t = iter.next();
    while (iter.hasNext()) {
        T t2 = iter.next();
        if (t.compareTo(t2) > 0) {
            return false;
        }
        t = t2;
    }
    return true;
}

Solution 4 - Java

Easy:

List tmp = new ArrayList(myList);
Collections.sort(tmp);
boolean sorted = tmp.equals(myList);

Or (if elements are comparable):

Object prev = null;
for( Object elem : myList ) {
    if( prev != null && prev.compareTo(elem) > 0 ) {
        return false;
    }
    prev = elem;
}
return true;

Or (if elements are not comparable):

Object prev = null;
for( Object elem : myList ) {
    if( prev != null && myComparator.compare(prev,elem) > 0 ) {
        return false;
    }
    prev = elem;
}
return true;

The implementations fail for lists containing null values. You have to add appropriate checks in this case.

Solution 5 - Java

If you need it for unit testing, you can use AssertJ. It contains an assertion to check if a List is sorted:

List<String> someStrings = ...
assertThat(someStrings).isSorted();

There is also an alternative method isSortedAccordingTo that takes a comparator in case you want to use a custom comparator for the sorting.

Solution 6 - Java

To check whether a list or any data structure for that matter is a task that only takes O(n) time. Just iterate over the list using the Iterator Interface and run through the data (in your case you already have it ready as a type of Comparable) from start to end and you can find whether its sorted or not easily

Solution 7 - Java

private static <T extends Comparable<? super T>> boolean isSorted(List<T> array){
	for (int i = 0; i < array.size()-1; i++) {
		if(array.get(i).compareTo(array.get(i+1))> 0){
			return false;
		}
	}
	return true;
}

zzzzz not sure guys what you guys are doing but this can be done in simple for loop.

Solution 8 - Java

Simply use the iterator to look through the contents of the List<T>.

public static <T extends Comparable> boolean isSorted(List<T> listOfT) {
    T previous = null;
    for (T t: listOfT) {
        if (previous != null && t.compareTo(previous) < 0) return false;
        previous = t;
    }
    return true;
}

Solution 9 - Java

Using Java 8 streams:

boolean isSorted = IntStream.range(1, list.size())
        .map(index -> list.get(index - 1).compareTo(list.get(index)))
        .allMatch(order -> order <= 0);

This also works for empty lists. It is however only efficient for lists that also implement the RandomAccess marker interface (e.g., ArrayList).

If you do not have access to the stream's underlying collection, the following ugly hack can be used:

Stream<T> stream = ...
Comparator<? super T> comparator = ...
boolean isSorted = new AtomicInteger(0) {{
    stream.sequential()
          .reduce((left, right) -> {
               getAndUpdate(order -> (order <= 0) ? comparator.compare(left, right) : order);
               return right;
          });
}}.get() <= 0;

Solution 10 - Java

This is an operation that will take O(n) time (worst case). You will need to handle two cases: where the list is sorted in descending order, and where the list is sorted in ascending order.

You will need to compare each element with the next element while making sure that the order is preserved.

Solution 11 - Java

This is what I would do:

public static <T extends Comparable<? super T>> boolean isSorted(List<T> list) {
    if (list.size() != 0) {
        ListIterator<T> it = list.listIterator();
        for (T item = it.next(); it.hasNext(); item = it.next()) {
            if (it.hasPrevious() && it.previous().compareTo(it.next()) > 0) {
                return false;
            }
        }

    }
    return true;
}

Solution 12 - Java

One simple implementation on arrays:

public static <T extends Comparable<? super T>> boolean isSorted(T[] a, int start, int end) {
	while (start<end) {
		if (a[start].compareTo(a[start+1])>0) return false;
		start++;
	}
	return true;
}

Converting for lists:

public static <T extends Comparable<? super T>> boolean isSorted(List<T> a) {
	int length=a.size();
	if (length<=1) return true;
	
	int i=1;
	T previous=a.get(0);
	while (i<length) {
		T current=a.get(i++);
		if (previous.compareTo(current)>0) return false;
		previous=current;
	}
	return true;
}

Solution 13 - Java

Here comes a method using an Iterable and a Comparator.

<T> boolean isSorted(Iterable<? extends T> iterable,
                     Comparator<? super T> comparator) {
    boolean beforeFirst = true;
    T previous = null;
    for (final T current : iterable) {
        if (beforeFirst) {
            beforeFirst = false;
            previous = current;
            continue;
        }
        if (comparator.compare(previous, current) > 0) {
            return false;
        }
        previous = current;
    }
    return true;
}

And a method for an Iterable of Comparable and a flag for ordering.

<T extends Comparable<? super T>> boolean isSorted(
        Iterable<? extends T> iterable, boolean natural) {
    return isSorted(iterable, natural ? naturalOrder() : reverseOrder());
}

Solution 14 - Java

IMO, from what I'm seeing, the complexity of checking this is as bad as performing the sort for a second time, and I understand people are short circuiting with returns if it is not sorted, but if the List is actually sorted, then the entire length will be traversed..., I'd argue to just let the code continue as if the List was sorted, and let the code itself figure out if it is or not.

I would recommend placing an Error detailing why the specific line that will fail is doing so because its collection is not reversed/ordered etc...

eg.

the line detachTailIndex.run() will give a NullPointerException(),

if (fromReversedMethod && detachTailIndex == null) {
throw new NullPointerException("detachTailIndex was null. \n 
Reason: The List<> is required to be reversed before submission")
}

Or if your plan is to use a conditional for when sorted or not the you can use the null to verify if it is sorted and choose the other option.

If there is no other option, then using the other responses are ok.

Here is another example:

    int key = entry.getKey();
    
    List<Integer> shouldBeReversed = entry.getValue();

    try {
        //If all entries need to be iterated better place them inside the Try-Catch
            updateBatch(key,
                    xes -> {
                        for (int rowIndex : shouldBeReversed
                        ) {
                            xes.remove((int) rowIndex); // will return an IndexOutOfBoundsException if not sorted in reverse
                        }
                        return xes;
                    }
            );
    } catch (IndexOutOfBoundsException e) {
        throw new IndexOutOfBoundsException(e.getMessage() + "\n" +
                "Reason: Batch indexes (Entry's value \"List<Integer>\") should be sorted in reverse order before submission");
    }

if conditional is required (on sorted, or on not sorted) then the catch() body could be used as a "not sorted" option.

Of course this is very very case specific, but seems that checking for a sorting order just to get a boolean seems too much (?) specially on iterations.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEric WilsonView Question on Stackoverflow
Solution 1 - JavaColinDView Answer on Stackoverflow
Solution 2 - JavaPalleView Answer on Stackoverflow
Solution 3 - JavaSeanView Answer on Stackoverflow
Solution 4 - JavaDanielView Answer on Stackoverflow
Solution 5 - JavaWim DeblauweView Answer on Stackoverflow
Solution 6 - JavabragboyView Answer on Stackoverflow
Solution 7 - JavadigitebsView Answer on Stackoverflow
Solution 8 - JavajjnguyView Answer on Stackoverflow
Solution 9 - JavasakraView Answer on Stackoverflow
Solution 10 - JavaVivin PaliathView Answer on Stackoverflow
Solution 11 - JavaYishaiView Answer on Stackoverflow
Solution 12 - JavamikeraView Answer on Stackoverflow
Solution 13 - JavaJin KwonView Answer on Stackoverflow
Solution 14 - JavaDelarkView Answer on Stackoverflow