用于同时变换地图和过滤空结果的惯用法

时间:2018-02-20 05:06:48

标签: kotlin

我尝试使用table = Map<K, V>映射f: (K) -> M?的键并获得Map<M, V>。但是,我所有的尝试都有点臭:

  • table.mapKeys{ f(it.key) }.filter{it != null} as Map<M, V>似乎最直接,但必须手动从Map<M?, V>投射到Map<M, V>。未经检查的演员回避了空检查&#34;生态系统&#34;,这似乎是关闭的(并导致IDE发出抱怨)。

  • table.filterKeys(f(it) != null).mapKeys(f)很简单,但适用f两次,感觉很愚蠢。

  • 我也考虑过table.mapNotNull { f(it.key)?.let {res -> res to it.value} }.toMap(),但创建中间列表非常缺乏吸引力。

我觉得应该有一种直截了当的声明(即没有MutableMap)方式来实现这种转变,但我无法找到它。

1 个答案:

答案 0 :(得分:3)

您可以为自己添加实用程序功能:

inline fun <K, V, R : Any> Map<K, V>.mapKeysNotNull(transform: (Map.Entry<K, V>) -> R?): Map<R, V> {
    return mapKeysNotNullTo(LinkedHashMap(), transform)
}

inline fun <K, V, R : Any> Map<K, V>.mapKeysNotNullTo(destination: MutableMap<R, V>, transform: (Map.Entry<K, V>) -> R?): Map<R, V> {
    forEach { element -> transform(element)?.let { destination.put(it, element.value) } }
    return destination
}

这是此代码的长版本,以尽可能地匹配标准库集合扩展实现的样式。您可以根据需要简化此操作,例如:

inline fun <K, V, R : Any> Map<K, V>.mapKeysNotNull(transform: (Map.Entry<K, V>) -> R?): Map<R, V> {
    val destination = LinkedHashMap<R, V>()
    forEach { element -> transform(element)?.let { destination.put(it, element.value) } }
    return destination
}

无论哪种方式,你尝试制作的电话都是这样的:

table.mapKeysNotNull(f)