hashmap kotlin 的不区分大小写的键?

Case insensitive key for hashmap kotlin?

我有一个以字符串为键、以整数为值的哈希图。我希望按键不区分大小写。

val items = HashMap<String, Int>()
    items["key1"] = 90
    items["Key1"] = 80
    items["C"] = 70
    for ((k, v) in items) {
        println("$k = $v")
    }

这将 key1 和 Key1 作为单独的条目

为此,您需要提供一些扩展功能,以某种定义的方式放置和获取条目(例如,每次使用 lowercase() 字符串的方法)保持键不区分大小写

fun HashMap<String, Int>.putInsensitive(k: String, v: Int) {
    this[k.lowercase()] = v
}

fun HashMap<String, Int>.getInsensitive(k: String, v: Int): Int? = this[k.lowercase()]

或者提供自己的Map接口实现(甚至可以继承自HashMap)

class InsensitiveHashMap<V> : HashMap<String, V>() {
    override fun put(key: String, value: V): V? = super.put(key.lowercase(), value)
    
    override fun get(key: String): V? = return super.get(key.lowercase())
}

尽管您可以使用 HashMap 的扩展来伪造它(如另一个答案中所述),但我认为这不是一个好的解决方案:为了使地图的行为完全一致,您可能需要重写很多方法。 (例如,如果您通过其 keySet 更新地图,则很难确保它保持不区分大小写。 在此过程中可能还有更多问题。)

在大多数情况下,您实际上并不需要特定的 HashMap — 您只需要 Map implementation.  And so an alternative is to use another type of map that lets you provide your own Comparator,例如:

val items = TreeMap<String, Int>{ a, b -> 
    a.toLowerCase().compareTo(b.toLowerCase())
}

TreeMap is an implementation of SortedMap — 一种特殊类型的 Map,它使键保持有序:它们的自然顺序或您提供的顺序。在这种情况下,我给出了一个简单的 Comparator 实现,它比较两个字符串的小写版本。

根据这个定义,问题中的其余代码运行良好,并打印出:

C = 70
key1 = 80

……即它已经认识到“Key1”应该被视为与“key1”相同,并更新了那个值而不是添加一个新值。我认为这就是您想要的行为。

您不需要考虑地图已排序的事实;那只是一个额外的好处。您仍然可以像对待任何其他 Map 实现一样对待它,一切都应该有效。

(这是另一个例子,说明为什么最好针对接口而不是实现进行编程。‹ 如果您编写的代码可以使用任何 Map 实现,则可以给它一个 HashMapTreeMap 或任何其他类型的地图,没有任何更改。)

@m.antkowicz 的答案变体,您实际上可以“覆盖”HashMap 本身的 get / put 运算符(并使其成为一个很棒的 footgun):


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
}