j2e*_*nue 7 sorting enums kotlin
在 Java 中,我们可以轻松地通过枚举对 Collection 进行排序,如下所示:
Collections.sort(toSortEnumList, new Comparator<theEnum>() {
@Override
public int compare(theEnum o1, theEnum o2) {
return o1.ordinal().compareTo(o2.ordinal());
}
});
Run Code Online (Sandbox Code Playgroud)
并且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())
Run Code Online (Sandbox Code Playgroud)
这打印:
美国、德国、中国、巴西
降序。不是我想要的。我想按密封类顺序(如 Java 枚举中的序数)排序,如下所示:
巴西、美国、德国、中国
我认为密封类应该比枚举更好,但如果我做不到这一点,也许枚举有优势。
更新:感谢罗兰的帮助,我找到了密封班级的列表。但现在我想按它排序:这是我到目前为止所拥有的:
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)
)
}
})
Run Code Online (Sandbox Code Playgroud)
但我在以下位置收到以下错误indexOf:
类型推断失败。类型参数 T 的值应该在输入类型(参数类型、接收者类型或预期类型)中提及。尝试明确指定它。
你可以给你GoodCountries一个order像这样的财产:
sealed class GoodCountries(val order: Int) {
class Brazil : GoodCountries(0)
class USA : GoodCountries(1)
class Germany : GoodCountries(2)
class China : GoodCountries(3)
}
Run Code Online (Sandbox Code Playgroud)
这不是一个完美的解决方案,因为您必须手动枚举,但这样可以保证所需的顺序。
这样做将大大简化您的比较代码:
val sorted = toSortList.sortedBy(GoodCountries::order)
println(sorted.map { it::class.simpleName })
Run Code Online (Sandbox Code Playgroud)
输出:
[巴西、美国、德国、中国]
编辑:用Chrispher的好主意进行更新,使代码更加清晰(order在构造函数中具有属性GoodCountries,而不是使其成为由子类覆盖的抽象变量)。
也许不完全是您正在寻找的,但也许它是......
虽然密封类似乎没有像序数之类的东西,您已经注意到了,但它本身是sealedSubclasses有的class(即GoodCountries::class.sealedSubclasses)。另外,似乎 的顺序sealedSubclasses是定义的类之一,即Brazil在此列表中总是第一,USA第二等。如果它们不是全部嵌套,则顺序会有所不同(即,如果有些在外部,则它们是首先列出)。
然而:文档并没有说明这个顺序是故意选择的。“密封类”参考文档和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...
Run Code Online (Sandbox Code Playgroud)
或类似的东西:
GoodCountries::class.sealedSubclasses
.asSequence()
.flatMap { klazzInOrder ->
entityList.asSequence().filter { it::class == klazzInOrder }
}
.forEach(::println)
Run Code Online (Sandbox Code Playgroud)
就性能而言,两者可能都不是最佳选择,但我想您已经明白了。
我之前添加的排序示例(当我没有意识到您实际上想要对实体而不是类型进行排序时):
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)
Run Code Online (Sandbox Code Playgroud)
您甚至可能想要组合nullsLastand CASE_INSENSITIVE_ORDER(最有可能的是,如果您不处理密封类),在这种情况下您会编写如下内容:
GoodCountries::class.sealedSubclasses.sortedWith(compareBy(nullsLast(String.CASE_INSENSITIVE_ORDER)) { it.simpleName })
.forEach(::println)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8235 次 |
| 最近记录: |