从枚举的所有值中初始化一个EnumMap。

5

我有一个枚举类:

enum class E { A, B, C, D }

如何以最简洁的方式初始化一个EnumMap以包含E的所有值作为键,每个键都有一个初始值为0?

val map = ...?
assert(map is EnumMap<E, Int>)
assert(map[E.A] == 0)
assert(map[E.B] == 0)
assert(map[E.C] == 0)
assert(map[E.D] == 0)

The most concise I could think of is:

val map = E.values().associateWithTo(EnumMap(E::class.java)) { 0 }

然而,重复使用名称 E 违反了DRY原则。并且单词 associateWithTo 有点啰嗦。是否有更简洁易读的方法?我希望有类似于EnumSet.allOf()EnumMap.allOf()

你真的需要它是一个EnumMap吗?Map不够用吗? - João Dias
2
这个地图将会被使用数十万次每秒。EnumMap 相当于数组索引。其他的地图会更低效:HashMap 会查找枚举值的哈希码并转到包含链接列表的表。 - k314159
3个回答

12

我能想到的最简单的方法是:

val map = EnumMap(E.values().associateWith { 0 })

1
是的,我认为这是最基本的了,没有重复,也不需要显式指定类型。如果你喜欢,你可以像这样链接它:E.values().associateWith { 0 }.run(::EnumMap)。如果你喜欢,你可以使用enumValues<E>(),就像@broot在实用函数中所做的那样。但是你需要吗?如果你经常这样做,那么可能需要,但我认为这很简单易懂! - cactustictacs
感谢@cactustictacs的提示。我也喜欢它原样,因为它看起来更易读,但我认为我们正在进入个人偏好的领域;) - João Dias
哦,那些评论是针对楼主的,不是你!因为他们正在寻找可能性。 - cactustictacs
是的,我理解了。不过,这些也是给我其他可能的方式的好提示。在同一个问题上拥有不同的观点总是很好的;) - João Dias
1
没问题!是的,我喜欢指出链式编程的事情,因为我认为这种函数管道方法有时更易读。即使这个很短,也很好能够从左到右阅读它,如“E -> 获取其值 -> 用每个值设置为0创建一个映射 -> 将其转换为EnumMap”。虽然在这里不一定更好,但就像你说的,这是个人偏好! - cactustictacs

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}

3

您可以始终为此目的创建自己的实用函数:

fun main() {
    val map = enumMap<E, Int> { 0 }
}

inline fun <reified E : Enum<E>, V> enumMap(valueSelector: (E) -> V): EnumMap<E, V> {
    return enumValues<E>().associateWithTo(EnumMap(E::class.java), valueSelector)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接