[英]Kotlin sealed class - how to sort by sealed class similar to sorting by enum
在 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 枚舉中的序數)排序,如下所示:
巴西、美國、德國、中國
我認為密封類應該比枚舉更好,但如果我不能這樣做,也許枚舉有優勢。
更新:多虧了羅蘭的幫助,我才能找到密封類的列表。 但現在我想按它排序:這是我目前所擁有的:
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)
)
}
})
但我在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)
}
這不是一個完美的解決方案,因為您必須手動枚舉,但這樣可以保證所需的順序。
這樣做將大大簡化您的比較代碼:
val sorted = toSortList.sortedBy(GoodCountries::order)
println(sorted.map { it::class.simpleName })
輸出:
[巴西、美國、德國、中國]
編輯:更新了Chrispher 的好主意,這使代碼更加清晰(在GoodCountries
構造函數中具有order
屬性,而不是使其成為被子類覆蓋的抽象變量)。
您的問題的快速答案是在比較器中切換x
和y
,即x::class.java.name.compareTo(y::class.java.name)
更長的答案是,對於您的用例,枚舉可能更好。 當某些子類看起來與其他子類不同時,密封類會發光,並且擁有它們的多個實例很有意義。 例如,帶有子類Success
和Error
的sealed class Result
,其中Success
保存數據, Error
保存異常。 假設您希望對所有國家/地區一視同仁,您的用例似乎更適合傳統枚舉。
也許不完全是你正在尋找的,但也許它是......
雖然密封類似乎沒有像序數這樣的東西,你已經注意到了,但class
本身有sealedSubclasses
(即GoodCountries::class.sealedSubclasses
)。 此外,似乎sealedSubclasses
的順序是定義的類之一,即此列表中的Brazil
始終排在第一位, USA
第二位,等等。如果它們不是全部嵌套(即,如果有些在外面,它們首先列出)。
但是:文檔並沒有說明這個順序是故意選擇的。 無論是在“密封類”參考文檔中,還是在sealedSubclasses
(k) 文檔中。
關於在密封類順序中對實體進行排序的問題,您可能需要使用以下內容:
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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.