从 Kotlin 中的值列表创建 EnumMap
Create EnumMap from List of values in Kotlin
我想定义 enum class
的扩展,它接受与枚举常量顺序相同的值列表并输出 EnumMap
。
我能够做的是创建和扩展 List<V>
对象,并使用来自 Enum<K>.values()
的键数组作为输入。
似乎困难在于 enum class
本身不是具有 .values()
方法的对象。所以也许我的要求不合理。
这是一个使用列表扩展方法的工作示例。
import java.util.*
enum class Shoes(
val title: String,
val weight: Double) {
WORKBOOT("tough", 11.0),
SNEAKER("fast", 6.0),
SLIPPER("soft", 3.0);
}
fun main(args: Array<String>) {
val prices= listOf(11.5,8.2,3.5)
val map = prices.enumMapOf(Shoes.values())
map.print()
}
inline fun <reified K : Enum<K>, V> List<V>.enumMapOf(keys:Array<K>): EnumMap<K, V> {
val map = EnumMap<K, V>(K::class.java)
keys.forEachIndexed{i,k-> map[k]=this[i]}
return map
}
fun <K:Enum<K>,V> EnumMap<K,V>.print() {
this.forEach{k,v-> println("%d: %s --> %.2f".format(k.ordinal,k.name,v)) }
}
我认为您缺少的主要是 enumValues
方法,它可以为您提供通用枚举的值。
这将允许您这样做(我也重新安排了创建 EnumMap
的代码,当然,如果这看起来太复杂,您可以坚持自己的解决方案):
inline fun <reified K : Enum<K>, V> Enum<K>.mappedTo(values: List<V>): EnumMap<K, V> {
return enumValues<K>().zip(values).toMap(EnumMap(K::class.java))
}
当然,现在这个问题是调用语法 - 这个函数必须像这样调用,在枚举的实例上:
Shoes.WORKBOOT.mappedTo(listOf(11.5, 8.2, 3.5))
这没有多大意义。打这个电话会更好:
Shoes.mappedTo(listOf(11.5, 8.2, 3.5))
但据我所知,没有办法实现这种语法,因为您不能向通用枚举的伴生对象添加扩展,然后期望在特定枚举的伴生对象上调用它 -那些不会像那样相互继承。
因此,也许您可以使用常规函数而不是创建扩展,并从通用参数而不是接收者获取枚举类型:
inline fun <reified K : Enum<K>, V> mapEnumTo(values: List<V>): EnumMap<K, V> {
return enumValues<K>().zip(values).toMap(EnumMap(K::class.java))
}
mapEnumTo<Shoes, Double>(listOf(11.5, 8.2, 3.5))
您也必须在此处指定键的类型,因为您不能先有一个显式的泛型类型参数,然后再有一个隐式的泛型类型参数。但我认为这是非常好的语法,因为您会看到正在创建的映射的键和值类型。
作为从@zsmb13 的回答中消除显式 Double
的解决方法,您可以借用标准的 Scala 技巧,将其分成两个具有不同类型参数列表的方法调用,其中一个是显式的,另一个是推断的:
interface EnumMapper<K : Enum<K>> {
operator fun <V> invoke(values: List<V>): EnumMap<K, V>
}
inline fun <reified K : Enum<K>> mapEnumTo() = object : EnumMapper<K> {
override operator fun <V> invoke(values: List<V>): EnumMap<K, V> {
return enumValues<K>().zip(values).toMap(EnumMap(K::class.java))
}
}
mapEnumTo<Shoes>()(listOf(11.5, 8.2, 3.5))
枚举本身:
private val shoeMap by lazy { values().associateBy { it.title } }
我想定义 enum class
的扩展,它接受与枚举常量顺序相同的值列表并输出 EnumMap
。
我能够做的是创建和扩展 List<V>
对象,并使用来自 Enum<K>.values()
的键数组作为输入。
似乎困难在于 enum class
本身不是具有 .values()
方法的对象。所以也许我的要求不合理。
这是一个使用列表扩展方法的工作示例。
import java.util.*
enum class Shoes(
val title: String,
val weight: Double) {
WORKBOOT("tough", 11.0),
SNEAKER("fast", 6.0),
SLIPPER("soft", 3.0);
}
fun main(args: Array<String>) {
val prices= listOf(11.5,8.2,3.5)
val map = prices.enumMapOf(Shoes.values())
map.print()
}
inline fun <reified K : Enum<K>, V> List<V>.enumMapOf(keys:Array<K>): EnumMap<K, V> {
val map = EnumMap<K, V>(K::class.java)
keys.forEachIndexed{i,k-> map[k]=this[i]}
return map
}
fun <K:Enum<K>,V> EnumMap<K,V>.print() {
this.forEach{k,v-> println("%d: %s --> %.2f".format(k.ordinal,k.name,v)) }
}
我认为您缺少的主要是 enumValues
方法,它可以为您提供通用枚举的值。
这将允许您这样做(我也重新安排了创建 EnumMap
的代码,当然,如果这看起来太复杂,您可以坚持自己的解决方案):
inline fun <reified K : Enum<K>, V> Enum<K>.mappedTo(values: List<V>): EnumMap<K, V> {
return enumValues<K>().zip(values).toMap(EnumMap(K::class.java))
}
当然,现在这个问题是调用语法 - 这个函数必须像这样调用,在枚举的实例上:
Shoes.WORKBOOT.mappedTo(listOf(11.5, 8.2, 3.5))
这没有多大意义。打这个电话会更好:
Shoes.mappedTo(listOf(11.5, 8.2, 3.5))
但据我所知,没有办法实现这种语法,因为您不能向通用枚举的伴生对象添加扩展,然后期望在特定枚举的伴生对象上调用它 -那些不会像那样相互继承。
因此,也许您可以使用常规函数而不是创建扩展,并从通用参数而不是接收者获取枚举类型:
inline fun <reified K : Enum<K>, V> mapEnumTo(values: List<V>): EnumMap<K, V> {
return enumValues<K>().zip(values).toMap(EnumMap(K::class.java))
}
mapEnumTo<Shoes, Double>(listOf(11.5, 8.2, 3.5))
您也必须在此处指定键的类型,因为您不能先有一个显式的泛型类型参数,然后再有一个隐式的泛型类型参数。但我认为这是非常好的语法,因为您会看到正在创建的映射的键和值类型。
作为从@zsmb13 的回答中消除显式 Double
的解决方法,您可以借用标准的 Scala 技巧,将其分成两个具有不同类型参数列表的方法调用,其中一个是显式的,另一个是推断的:
interface EnumMapper<K : Enum<K>> {
operator fun <V> invoke(values: List<V>): EnumMap<K, V>
}
inline fun <reified K : Enum<K>> mapEnumTo() = object : EnumMapper<K> {
override operator fun <V> invoke(values: List<V>): EnumMap<K, V> {
return enumValues<K>().zip(values).toMap(EnumMap(K::class.java))
}
}
mapEnumTo<Shoes>()(listOf(11.5, 8.2, 3.5))
枚举本身: private val shoeMap by lazy { values().associateBy { it.title } }