Kotlin Map:为什么没有 toHashMap()?
Kotlin Map: why is there no toHashMap()?
在 Kotlin 中,Map
class 有 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,最简单的实现会进行强制转换 as HashMap
,否则进行转换。因此,在更改实现的情况下,该代码的性能将发生巨大变化。太糟糕了。
所以,恕我直言,我更喜欢不安全的转换,如果 stdlib
以一种奇怪的方式发生变化并提醒我这一点,它就会失败。
无论如何,随时欢迎您在 YouTrack http://youtrack.jetbrains.com/issues/KT 中将此问题作为工单报告。您在这里对问题进行了很好的描述,所以应该不会花很长时间。
如何像这样过滤它:
val filtered = matchesInClass.mapValues { it.value.filterKeys { it !in banned } }
为什么? 很难回答,但搜索 Kotlin issue tracker 或向 Kotlin issue tracker 添加工单将为您提供答案,并在状态发生变化时通知您。似乎缺少 toHashMap
因为 toHashSet
在那里(截至 1.0 BETA 4)。
注意: LinkedHashMap 是默认值,因为 kotlin 希望在您从 List
到 Set
再到 [=13= 时保持元素的顺序] 到 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 } //error: not a 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 })
}
在 Kotlin 中,Map
class 有 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,最简单的实现会进行强制转换 as HashMap
,否则进行转换。因此,在更改实现的情况下,该代码的性能将发生巨大变化。太糟糕了。
所以,恕我直言,我更喜欢不安全的转换,如果 stdlib
以一种奇怪的方式发生变化并提醒我这一点,它就会失败。
无论如何,随时欢迎您在 YouTrack http://youtrack.jetbrains.com/issues/KT 中将此问题作为工单报告。您在这里对问题进行了很好的描述,所以应该不会花很长时间。
如何像这样过滤它:
val filtered = matchesInClass.mapValues { it.value.filterKeys { it !in banned } }
为什么? 很难回答,但搜索 Kotlin issue tracker 或向 Kotlin issue tracker 添加工单将为您提供答案,并在状态发生变化时通知您。似乎缺少 toHashMap
因为 toHashSet
在那里(截至 1.0 BETA 4)。
注意: LinkedHashMap 是默认值,因为 kotlin 希望在您从 List
到 Set
再到 [=13= 时保持元素的顺序] 到 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 } //error: not a 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 })
}