Collection processing in Kotlin: Sorting, shuffling and reversing
To have your collection elements organized in a concrete order, we can use sorting functions:
sorted can only be used on a list of elements with natural order for elements that implement the
Comparable interface. The most important types with natural order are:
Doubleand other basic classes representing numbers that are sorted from the lowest number to the highest.
Charis treated as a number in UTF-16 code under the hood, so comparing two characters is like comparing their codes. Letters are organized in alphabetical order, but capital letters always come before lowercase letters. A space comes before all letters.
String, whose natural order is lexicographical (this is a generalization of the alphabetical order that is used in dictionaries), where we start from comparing the first character (according to
Charorder); whenever two characters are equal, we are shifting the burden of the decision to the next character.
true. This is because
trueare typically represented by
1, respectively, and the natural order for numbers places
Kotlin standard library sorting functions are implemented in the way, so that equal elements remain in the same order (so we say that a stable sorting algorithm is being used).
To reverse the order of the elements in the list, use the
To reverse the sorting order, we can use the
sortedDescending function, which gives the same result as first using
sorted and then
If we want to sort elements by one of their properties, we should use
sortedBy, which sorts elements by the value its selector returns. For instance, if we have a list of students and we want to sort them by the semester, we can use
sortedBy with a selector that reads the semester value.
In other words, in
sortedBy, the selector decides what value should be compared when we sort elements. This value needs to be comparable to itself (implement
sortedBy also has a descending alternative called
We might use
sortedByDescending to sort users by their login, news by publication date, or tasks by priority.
The selectors of
null, which is considered less than all other values.
It gets more complicated when we need to sort by more than one property. For example, a typical governmental order of people’s names requires sorting them by their surnames, and then people with the same surnames should be sorted by their first names. How can we implement this? Sorting by name first and then by surname would give us the correct result, but would be terribly inefficient. A much better solution is using
sortedWith is a function that returns a collection sorted according to a comparator it receives as an argument. The comparator is an object that implements the
In many languages, it is popular to make an object that implements a comparator.
We can do that in Kotlin too, but in most cases it is better to use one of the top-level functions from the standard library. For instance, we can use
compareBy to create a comparator that first compares using one selector; then, if it considers two objects equal, it compares values using the next selector. This way, we can make a comparator with multiple sorting selectors, used lexicographically.
sortedBy(selector)under the hood is just
compareBy can be used for as many selectors as we want, which makes them really universal for complex sorting.
When we need to construct a different comparator, we have a variety of standard library functions. We can create a new comparator using:
naturalOrder(sorts with natural order),
reverseOrder(sorts with the reverse of natural order),
nullsLast(both use natural order, but they also place nulls first or last).
Then, when we have a comparator, we can modify it using functions on
Comparator, such as:
thenComparator, both of which add another comparator that is used when the previous comparator considers elements equal;
thenBy, which compares values using a selector when the previous comparator considers elements equal;
reversed, which reverses the comparator order.
Sorting mutable collections
If you want to sort a mutable collection, you can use the
sort function. This is a part of classic collection processing as it modifies a mutable list instead of returning a processed one. The
sort method is often confused with
sort method is an extension function on
MutableList that, in contrast to
sorted, sorts a list and returns
sorted method is an extension function on
Iterable that does not modify its receiver and returns a sorted collection.
There are also
sortWith, which respectively work similarly to
sortedWith, but they modify a mutable collection instead of returning a new one.
Maximum and minimum
Another common situation is that we need to find extremes in a collection: the biggest or the smallest element. We could first sort the elements and then take the first or the last one, but such a solution would be far from optimal. Instead, we should use functions that start with the "max" or "min" prefix.
If we want to find an extreme using the natural order of the elements, use
minOrNull, both of which return
null when a collection is empty.
If we want to find an extreme according to a selector (similar to
You can also find an extreme according to a comparator. In such a case, use
Another case is when you want to find an extreme value of a property: not the element that contains the extreme value but the value itself. For example, you have a list of students and you want to find their highest score. You could map the students to scores and then find the maximal value, or you could find the student with the highest score and get this score. However, both of these options do a lot of unnecessary operations. Instead, we should use the
minOfOrNull method with a selector that extracts a score (or
minOf if you are sure that your collection is not empty).
We have learned how to sort elements, but we might also want to shuffle them. To get a random number from a collection, use
randomOrNull for possibly empty lists). To shuffle an iterable (to make its order random), use
shuffled. For these functions, you can pass a custom
Random object as an argument.