我有一个哈希图,以字符串为键,以整数为值。我希望键不区分大小写。
val items = HashMap<String, Int>()
items["key1"] = 90
items["Key1"] = 80
items["C"] = 70
for ((k, v) in items) {
println("$k = $v")
}
这将 key1 和 Key1 作为单独的条目
答案 0 :(得分:4)
为此,您需要提供一些扩展函数,以某种定义的方式放置和获取条目(例如使用 everytime toLowerCase()
String 的方法)保持键不区分大小写
fun HashMap<String, Int>.putInsensitive(k: String, v: Int) {
this[k.toLowerCase()] = v
}
fun HashMap<String, Int>.getInsensitive(k: String, v: Int): Int? = this[k.toLowerCase()]
或提供您自己的 Map
接口实现(它甚至可以从 HashMap 继承)
class InsensitiveHashMap<V> : HashMap<String, V>() {
override fun put(key: String, value: V): V? {
return super.put(key.toLowerCase(), value)
}
override fun get(key: String): V? {
return super.get(key.toLowerCase())
}
}
答案 1 :(得分:2)
尽管您可以使用 HashMap 的扩展来伪造它(如另一个答案中所述),但我认为这不是一个好的解决方案:为了使地图的行为完全一致,您可能需要覆盖很多方法。 (例如,如果您通过 keySet 更新地图,将很难确保它保持不区分大小写。 并且可能还有更多问题。)
在大多数情况下,您并不真正需要专门的 HashMap
— 您只需要一个 Map
实现。因此,另一种选择是使用另一种类型的地图,让您提供自己的Comparator
,例如:
val items = TreeMap<String, Int>{ a, b ->
a.toLowerCase().compareTo(b.toLowerCase())
}
TreeMap
是 SortedMap
的一种实现——一种特殊类型的 Map
,它保持其键的顺序:要么是它们的自然顺序,要么是您提供的顺序。在本例中,我给出了一个简单的 Comparator
实现,用于比较两个字符串的小写版本。
有了这个定义,问题中的其余代码运行良好,并打印出来:
C = 70
key1 = 80
...即它已经认识到“Key1”应该被视为与“key1”相同,并更新该值而不是添加一个新值。我认为这是您想要的行为。
您不需要考虑地图已排序的事实;这只是一个额外的好处。您仍然可以像对待任何其他 Map
实现一样对待它,一切都应该可以正常工作。
(这是另一个例子,说明为什么最好对接口进行编程,而不是实现。 如果您编写的代码可以使用任何 Map
实现,您可以给它一个 HashMap
或TreeMap
或任何其他类型的地图,无需任何更改。)
答案 2 :(得分:0)
@m.antkowicz 的答案的变体,您实际上可以“覆盖”HashMap
本身的 get/put 运算符(并使其成为一个很棒的足球):
operator fun HashMap<String, Int>.get(k: String): Int? = this[k.toLowerCase()]
operator fun HashMap<String, Int>.set(k: String, v: Int): Int? {
val originalK = this[k.toLowerCase()]
this.put(k.toLowerCase(), v )
return originalK
}
现在您可以:
fun main() {
val items = HashMap<String, Int>()
items["key1"] = 90
items["Key1"] = 80
items["C"] = 70
for ((k, v) in items) {
println("$k = $v")
}
// Prints:
// key1 = 80
// c = 70
}