如何使用 Kotlin 可用的便捷方法在末尾按多个值和空值对 collection 进行排序

How to sort a collection by multiple values AND nulls at the end using the available convenient methods of Kotlin

我以前使用过sortedWithcompareBy方法,它能够使用多个参数进行排序。

我之前也用过nullsLast方法,和其他两个一样方便。

但是,使用这些方法,我想不出一种方法来使用以下排序规则对 collection 进行排序:

鉴于 Class:

data class MyClass(
    val varA: String?,
    val varB: String
)

假设我有以下 collection:

val collection = listOf(
    MyClass(null, "A"),
    MyClass("a", "B"),
    MyClass("c", "C"),
    MyClass("b", "D"),
    MyClass("", "E"),
    MyClass("a", "F"),
    MyClass("b", "G"),
    MyClass(null, "H"),
    MyClass("", "I")
)

它应该被排序为:

    MyClass("a", "B")
    MyClass("a", "F")
    MyClass("b", "D")
    MyClass("b", "G")
    MyClass("c", "C")
    MyClass(null, "A")
    MyClass("", "E")
    MyClass(null, "H")
    MyClass("", "I")

有没有我可以使用的 one-liner 代码,就像使用 vararg 参数

compareBy 一样

当然有一条线:

collection.sortedBy {if(it.varA != null && it.varA.isNotEmpty()) it.varA + it.varB else "z" + it.varB}

然后打印出来:

output.forEach { println("Myclass(${it.varA}, ${it.varB})") }

输出:

Myclass(a, B)
Myclass(a, F)
Myclass(b, D)
Myclass(b, G)
Myclass(c, C)
Myclass(null, A)
Myclass(, E)
Myclass(null, H)
Myclass(, I)

解释:

我们需要在按 varA 排序和按 varB 排序时拆分案例。这就是为什么有一个条件 if(it.varA != null && it.varA.isNotEmpty()),它表示只有当它的值不是 null"".

时,我们才会按 varA 排序

否则,我们按字符串"z" + it.varB排序,这意味着我们按varB排序,带有z前缀,这将确保这些项目位于已排序集合的末尾。

为了更容易理解它是如何工作的,您可以试试下面的代码:

    val output = collection.map { if(it.varA != null && it.varA.isNotEmpty()) it.varA + it.varB else "z" + it.varB }

    output.sortedBy { it }.forEach { println(it) }

这个将输出这些字符串:

aB
aF
bD
bG
cC
zA
zE
zH
zI

现在应该更明显了。 :-)

我会这样做(参见 kotlin.comparisons documentation):

val comparator = compareBy<String, MyClass>(nullsLast(), { it.varA.let { if (it == "") null else it } }).thenBy { it.varB }

collection.sortedWith(comparator)