Запечатанный класс Kotlin - как сортировать запечатанным классом, подобным сортировке по enum - PullRequest
0 голосов
/ 09 декабря 2018

в java мы можем легко отсортировать коллекцию по enum с чем-то вроде этого:

Collections.sort(toSortEnumList, new Comparator<theEnum>() {
                @Override
                public int compare(theEnum o1, theEnum o2) {
                    return o1.ordinal().compareTo(o2.ordinal());
                }
            });

и toSortEnumList будет упорядочен по возрастанию.Как я могу сделать это с закрытым классом Kotlin?Вот что я пробовал до сих пор, я пытался сортировать по именам классов, но это не по позиции enum.Должен быть какой-то способ сортировки по позиции enum:

    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())

это печатает:

США Германия, Китай, Бразилия - по убыванию.не то, что я хочу.Я хочу отсортировать по порядку запечатанных классов (например, по порядковому номеру в enum 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))
            }
        })

но я получаю следующую ошибку:

enter image description here

Ответы [ 3 ]

0 голосов
/ 10 декабря 2018

Может быть, не совсем то, что вы ищете, но, возможно, это ...

Хотя запечатанные классы, похоже, не имеют чего-то вроде ординала, который вы уже заметили, есть sealedSubclasses на самом class (т.е. 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)
0 голосов
/ 08 января 2019

Вы можете присвоить свойству 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 })

Вывод:

[Бразилия, США, Германия, Китай]

0 голосов
/ 09 декабря 2018

Быстрый ответ на ваш вопрос состоит в том, чтобы переключить x и y в компараторе, то есть x::class.java.name.compareTo(y::class.java.name)

Чем длиннее ответ, тем лучше для вас вариант использования enum.Запечатанные классы сияют, когда некоторые подклассы выглядят не так, как другие, и имеет смысл иметь их несколько экземпляров.Например, sealed class Result с подклассами Success и Error, где Success содержит данные, а Error содержит исключение.Предполагая, что вы хотите относиться ко всем странам одинаково, ваш вариант использования может оказаться более подходящим для традиционного перечисления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...