在Java中,我们可以轻松地按枚举对集合进行排序,如下所示:
Collections.sort(toSortEnumList, new Comparator<theEnum>() {
@Override
public int compare(theEnum o1, theEnum o2) {
return o1.ordinal().compareTo(o2.ordinal());
}
});
和toSortEnumList将按升序排序。如何使用Kotlin密封课程来做到这一点?到目前为止,这是我尝试过的,但我尝试过按类名排序,但不是按枚举位置排序。必须有某种方式来按枚举位置排序:
sealed class GoodCountries {
class Brazil : GoodCountries() {}
class USA : GoodCountries() {}
class Germany : GoodCountries() {}
class China : GoodCountries() {}
}
//later on
var toSortList = listOf<GoodCountries>(China(), Brazil(), USA(), Germany())
Collections.sort(
toSortList,
{ x: GoodCountries, y: GoodCountries -> y::class.java.name.compareTo(x::class.java.name) })
Log.v("myTag", toSortList.toString())
此打印:
美国德国,中国,巴西-降序排列。不是我想要的。我想按密封类顺序排序(如枚举Java中的序数),我认为密封类应该比枚举更好,但是如果我做不到,也许枚举有优势。有人可以帮忙吗?
但我要打印:巴西,美国,德国,中国
更新:感谢Roland帮助我找到了密封类的列表。但现在我想按它排序:这是我到目前为止的内容:
Collections.sort(toSortList, object : Comparator<GoodCountries> {
override fun compare(left: GoodCountries, right: GoodCountries): Int {
return Integer.compare(GoodCountries::class.sealedSubclasses.indexOf(left), GoodCountries::class.sealedSubclasses.indexOf(right))
}
})
但出现以下错误:
答案 0 :(得分:2)
您的问题的快速答案是在比较器中切换x
和y
,即x::class.java.name.compareTo(y::class.java.name)
较长的答案是,对于您的用例,枚举可能更好。当某些子类看上去与其他子类不同时,密封类就会发光,拥有多个子类实例是有意义的。例如,具有子类sealed class Result
和Success
的{{1}},其中Error
保存数据,而Success
保存异常。假设您希望所有国家一视同仁,您的用例似乎更适合于传统枚举。
答案 1 :(得分:2)
您可以给GoodCountries
一个order
属性,并在子类中覆盖它,如下所示:
sealed class GoodCountries {
abstract val order: Int
class Brazil : GoodCountries() { override val order = 0 }
class USA : GoodCountries() { override val order = 1 }
class Germany : GoodCountries() { override val order = 2 }
class China : GoodCountries() { override val order = 3 }
}
这不是一个完美的解决方案,因为您必须手工枚举,但是这样可以保证所需的顺序。
这样做可以大大简化您的比较代码:
val sorted = toSortList.sortedBy(GoodCountries::order)
println(sorted.map { it::class.simpleName })
输出:
[巴西,美国,德国,中国]
答案 2 :(得分:1)
也许不是您想要的东西,但也许是...
虽然密封类似乎没有序数,但是您已经注意到,class
本身(即GoodCountries::class.sealedSubclasses
)上有sealedSubclasses
。同样,似乎sealedSubclasses
的顺序是已定义的类之一,即此列表中的Brazil
始终排在第一位,USA
其次,依此类推。如果它们并非全部嵌套(例如,如果其中一些在外部,则它们会首先列出)。
但是:文档没有指出此顺序是故意选择的。在'Sealed classes' reference documentation和sealedSubclasses
(k)documentation中都没有。
关于按密封的类顺序对实体进行排序的问题,您可能需要使用以下内容:
val entityList = listOf(Germany(), China(), USA(), Brazil(), Germany())
entityList.sortedBy { // or use sortedWith(compareBy {
GoodCountries::class.sealedSubclasses.indexOf(it::class)
}.forEach(::println) // or toList...
或类似的东西
GoodCountries::class.sealedSubclasses
.asSequence()
.flatMap { klazzInOrder ->
entityList.asSequence().filter { it::class == klazzInOrder }
}
.forEach(::println)
在性能方面,两者都不是最好的选择,但我想您会明白的。
我之前添加的排序样本(当我没有意识到实际上要对实体而不是类型进行排序时):
println("Listing the sealed classes in the order of their declaration*")
GoodCountries::class.sealedSubclasses.forEach(::println)
println("Listing the sealed classes ordered by their simple name")
GoodCountries::class.sealedSubclasses.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.simpleName!! })
.forEach(::println)
// same result, but written differently
GoodCountries::class.sealedSubclasses.sortedBy { it.simpleName?.toLowerCase() }
.forEach(::println)
您甚至可能希望结合使用nullsLast
和CASE_INSENSITIVE_ORDER
(很可能是在不使用密封类的情况下),在这种情况下,您可能会编写如下内容:
GoodCountries::class.sealedSubclasses.sortedWith(compareBy(nullsLast(String.CASE_INSENSITIVE_ORDER)) { it.simpleName })
.forEach(::println)