Search code examples
sortingkotlincomparatorcomparable

How does compareBy work in kotlin using a boolean expression


I know from official documentation that compareBy creates a comparator using the sequence of functions to calculate a result of comparison. The functions are called sequentially, receive the given values a and b and return Comparable objects.

I know how this must be done for normal attributes like the integer value here, but how are boolean conditions handled by compareBy?

In this example, I intended to keep all 4's at the top of the list and then sort in ascending order of values, but I am not sure how this boolean expression helps me do this!

fun main(args: Array<String>) {
    var foo = listOf(2, 3, 4, 1, 1, 5, 23523, 4, 234, 2, 2334, 2)
    
    foo = foo.sortedWith(compareBy({
        it != 4
    },{
        it
    }))
    
    print(foo)
}

Output

[4, 4, 1, 1, 2, 2, 2, 3, 5, 234, 2334, 23523]

Solution

  • Your code provides two selectors as a vararg to compareBy :

    foo.sortedWith(
            compareBy(
                { it != 4 },
                { it }
            )
    )
    
    

    Digging into the sources we have a Comparator for any two values a and b built up: Comparator { a, b -> compareValuesByImpl(a, b, selectors) }

    and finally:

    private fun <T> compareValuesByImpl(a: T, b: T, selectors: Array<out (T) -> Comparable<*>?>): Int {
        for (fn in selectors) {
            val v1 = fn(a)
            val v2 = fn(b)
            val diff = compareValues(v1, v2)
            if (diff != 0) return diff
        }
        return 0
    }
    

    The last code snippet demonstrates that if all selectors have the same diff, a and b are considered equal otherwise the first selector with diff != 0 wins.

    Booleans are comparable. When comparing 4 with any other value, say 2, you will have:

    4 != 4 false
    2 != 4 true
    diff = false.compareTo( true ) == -1
    

    and so, for sorting, 4 is "less" then any value that is not 4