3

In Kotlin, is there any concise way to generate a Comparable#compareTo() function for an interface that just calls this.property1.compareTo(that.property1) for each property of the interface in declaration order? Obviously, every property of the interface implements Comparable.

For interface I, it looks like I can create a top-level val like:

private val COMPARATOR = compareBy<I>(
    {it.property1},
    {it.property2},
    {it.property3},
    ...
)

And return COMPARATOR.compare(this, other) from I#compareTo(I), but, is there any simpler way to do this?

XDR
  • 4,070
  • 3
  • 30
  • 54

1 Answers1

1

You can use reflection and some simple language features like so:

inline fun <reified T : Any> compareByAll(): Comparator<T> {
    val selector = T::class.memberProperties
        .map { { i: T -> it.get(i) as Comparable<*> } }
        .toTypedArray()
    return compareBy(*selector)
}

Used like this:

val testInput = listOf(I(1, 2, 3), I(1, 2, 4), I(1, 0, 4), I(2, 3, 4), I(0, 1, 2)
testInput.sortedWith(compareByAll()))

Note that this solution doesn't handle the case that a property is not Comparable.

s1m0nw1
  • 76,759
  • 17
  • 167
  • 196
  • `T::class.memberProperties` seems to return the properties sorted alphabetically. I want them in declaration order so I can easily control the property comparison order, as that affects the return value. Also, is there any way to limit the iterated properties to those in the primary constructor, not all properties of the class? (I know my question didn't ask the latter part, but I just thought of some derived properties that I'd like to add that aren't necessary for comparisons) – XDR Jun 04 '18 at 15:16