#kotlin #enum-map
Вопрос:
У меня есть класс перечисления:
enum class E { A, B, C, D }
Каков самый простой способ инициализации карты перечисления, содержащей все значения E в качестве ключей, каждое из которых имеет начальное значение 0?
val map = ...? assert(map is EnumMaplt;E, Intgt;) assert(map[E.A] == 0) assert(map[E.B] == 0) assert(map[E.C] == 0) assert(map[E.D] == 0)
Самое краткое, что я мог придумать, это:
val map = E.values().associateWithTo(EnumMap(E::class.java)) { 0 }
Однако повторение названия E
нарушает СУХОЙ принцип. И это слово associateWithTo
немного набито ртом. Есть ли более краткий и читаемый способ? Я бы хотел, чтобы было EnumMap.allOf()
что-то похожее на то, что есть EnumSet.allOf()
.
Комментарии:
1. Вам действительно нужно, чтобы это было
EnumMap
?Map
разве этого недостаточно?2. Эта карта будет использоваться сотни тысяч раз в секунду. Карта перечисления будет эквивалентна индексу массива. Другие карты были бы менее эффективными: hashmap будет искать хэш-код значения перечисления и переходить к таблице, содержащей связанный список.
Ответ №1:
Самый простой способ, который я могу придумать, это:
val map = EnumMap(E.values().associateWith { 0 })
Комментарии:
1. Да, это так просто, как я думаю, без повторений и без необходимости явно указывать типы. Вы могли бы приковать его
E.values().associateWith { 0 }.run(::EnumMap)
цепью, если хотите. И вы можете использоватьenumValueslt;Egt;()
, если это ваше дело, как это делает @broot в идее полезной функции. Но нужен ли он вам? Если вы делаете это часто, то, возможно, но это довольно просто и читабельно, я думаю!2. Спасибо за подсказки @cactustictacs. Я также предпочитаю его как есть просто потому, что он кажется более читабельным, но я бы сказал, что мы вступаем в область личных предпочтений 😉
3. О, эти комментарии были адресованы оператору, а не вам! Так как они ищут возможности и все такое
4. Да, я понял. Тем не менее, они также были хорошими подсказками мне о других возможных способах сделать это. Всегда хорошо иметь разные точки зрения на одну и ту же проблему 😉
5. Ах да, не беспокойтесь! И да, мне нравится указывать на цепочку, потому что этот функциональный конвейерный подход иногда может быть немного более читабельным, я думаю. Несмотря на то, что эта довольно короткая, приятно иметь возможность читать ее слева направо как
E -gt; get its values -gt; make a map with each one set to 0 -gt; turn that into an EnumMap
. Не обязательно лучше здесь, но, как вы сказали, личные предпочтения!
Ответ №2:
Вы всегда можете создать свою собственную полезную функцию для этой цели:
fun main() { val map = enumMaplt;E, Intgt; { 0 } } inline fun lt;reified E : Enumlt;Egt;, Vgt; enumMap(valueSelector: (E) -gt; V): EnumMaplt;E, Vgt; { return enumValueslt;Egt;().associateWithTo(EnumMap(E::class.java), valueSelector) }
Ответ №3:
val map = EnumMap(EnumSet.allOf(E::class.java).associateWith { 0 }) // {A=0, B=0, C=0, D=0}
Или, если вам нужна карта с «порядковым номером» (позиция в перечислении):
val map = EnumMap(EnumSet.allOf(E::class.java).associateWith(E::ordinal)) // {A=0, B=1, C=2, D=3}
Это будет версия для перечислений с пользовательскими свойствами:
enum class E(val value: String) { A("AAA"), B("BBB"), C("CCC"), D("DDD") } val map = EnumMap(EnumSet.allOf(E::class.java).associateWith(E::value)) // {A=AAA, B=BBB, C=CCC, D=DDD}