Инициализируйте карту перечисления из всех значений перечисления

#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}