Kotlin地图:为什么没有toHashMap()?
在Kotlin中, Map
类有toLinkedMap()
和toSortedMap()
扩展方法。
但为什么没有toHashMap()
方法? 实际上,许多stdlib方法的Map
实现是LinkedHashMap
,但是在我的代码中将其转换为HashMap
会使我依赖于不好的实现。
引入这样的方法会使开发人员无法深入实现,而在目前的实现中,它只是执行演员。
我的用例是:
val matchesInClass: HashMap<MessageClass, HashMap<Int, Int>> //... for ((cl, matches) in matchesInClass) { matchesInClass[cl] = matches.filterKeys { it !in banned } //error: not a HashMap }
当我使用HashMap(matches.filterKeys { it !in banned })
,会导致创建一个新地图的开销,我很乐意避免。
那么,是由设计?
我同意在stdlib这个地方是不方便的。 但是你怎么想要这样一个函数来实现toHashMap()
呢?
如果底层映射是HashMap,那么最简单的实现就是HashMap,否则就进行转换。 因此,在更改实现的情况下,该代码的性能将发生显着变化。 那很糟。
所以,恕我直言,我更喜欢不安全的演员,如果stdlib
以一种奇怪的方式变化,并提醒我这个失败。
无论如何,你总是欢迎在YouTrack http://youtrack.jetbrains.com/issues/KT作为票证报告这个问题。 你对这个问题做了一个很好的描述,所以不用多久。
为什么? 很难回答,但是为Kotlin问题跟踪器搜索或添加票据将会得到您的答案,并在状态更改时更新您的答案。 它似乎没有toHashMap
丢失,因为toHashSet
在那里(1.0 BETA 4)。
注意: LinkedHashMap是默认的,因为kotlin在从List
到Set
到List
到Map
到List
过程中想要维护元素的顺序,并确保事物仍然处于相对顺序。
无论如何,与此同时,这里是一个为您定制的toHashMap
:
public fun <K, V> Iterable<Pair<K, V>>.toHashMap(): Map<K, V> = HashMap<K, V>(collectionSizeOrNull() ?: 16).apply { putAll(this@toHashMap) }
您可以使用类似于toMap
函数的逻辑来选择最佳的初始地图大小,或者不要设置它并相信默认的增长实现。
Kotlin的构建很容易扩展。 如果一切都放到stdlib中,那么受限制的设备(如Android)上的用户就会抱怨它太大了,而且大多数人所要求的东西都是小问题,只是将几行代码放到自定义库中。
这不是对您的原始问题的答案,而是您的使用案例的替代解决方案。
在这里,你试图过滤HashMap<Int, Int>
并将其分配回它从中获取的映射:
matchesInClass [cl] = matches.filterKeys {it!in banned} //错误:不是一个HashMap
如果你没有要求保持matches
HashMap不变,你可以通过调用它的keys
可变集removeAll
函数就地过滤它:
val matchesInClass: HashMap<MessageClass, HashMap<Int, Int>> //... for (matches in matchesInClass.values) { matches.keys.removeAll { it in banned } // notice the inverted condition }
这比创建过滤副本更有效率。
另一种方法是使用Map.filterTo
提供一个所需类型的空映射:
for (entry in matchesInClass) { entry.setValue(entry.value.filterTo(HashMap()) { it !in banned }) }
如何过滤它像这样:
val filtered = matchesInClass.mapValues { it.value.filterKeys { it !in banned } }