Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using condition to select the sorting property in Kotlin

Tags:

kotlin

I am using sortedBy() to perform sorting on the collection of objects.

Since the order may change depending on the user choice, I've ended up with the following code

val sortedList = if (sortingOrder == WordSortingOrder.BY_ALPHA) {
                    list.sortedBy { it.word.value }
                } else {
                    list.sortedBy { it.createdAt }
                }

Then I perform further actions on the sorted collection. I realize that sortedBy() method expects a property to be returned. I wonder if there is a way to embed the sorting condition in one chain of collection methods.

like image 290
k_shil Avatar asked Aug 08 '16 12:08

k_shil


2 Answers

If your properties are of different types you won't be able to select one of them based on some condition as a result for sortedBy, as their common supertype would be inferred as Any and it is not a subtype of Comparable<R> as sortedBy expects.

Instead you can utilize sortedWith method, which takes a Comparator, and provide a comparator depending on the condition:

list.sortedWith(
    if (sortingOrder == WordSortingOrder.BY_ALPHA)
        compareBy { it.word.value }
    else
        compareBy { it.createdAt }
)

Comparators for different properties are created here with the kotlin.comparisons.compareBy function.

You can then extract the logic which selects comparator based on sorting order to a function:

list.sortedWith(comparatorFor(sortingOrder))

fun comparatorFor(sortingOrder: WordSortingOrder): Comparator<MyType> = ...
like image 190
Ilya Avatar answered Nov 09 '22 06:11

Ilya


The sortedBy expects any function of type (T) -> R as its parameter. A property is a corner case of that.

Which means you can do this:

val sortedList = list
    .sortedBy { if (sortingOrder == WordSortingOrder.BY_ALPHA) it.word.value else it.createdAt}

Or, if you need something more OOP-ish:

enum class WordSortingOrder(val transform: (MyObject) -> Int) {
    BY_ALPHA({it.word.value}), 
    BY_ALPHA_REVERSED({-1 * it.word.value}),
    DEFAULT({it.createdAt})
}

val sortedList = list.sortedBy { sortingOrder.transform(it)}
like image 25
voddan Avatar answered Nov 09 '22 07:11

voddan