科特林中的默认地图

科特林是否有默认地图?

Have you ever used a 默认 map or 默认 dict before? If you know Python a bit, you probably saw its 默认dict in action at some point. 科特林 also comes with a similar tool which I want to demonstrate in this little 文章.
You can find the Python 默认dict documentation and some examples 这里 但以下片段显示了基本的用例:

from collections import 默认dict 

d = 默认dict(int)
print(d["someKey"]) //0

The 默认dict can also be used with other types and makes sure that you don't get a KeyError when running your code. Instead, it provides a 默认 value for unknown keys, which can be really helpful for grouping and counting algorithms like the following one:

from collections import 默认dict 

data = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
d = 默认dict(set)
for k, v in data:
    d[k].add(v)

print(d.items()) # dict_items([('red', {1, 3}), ('blue', {2, 4})])

在这篇文章中,我想向您展示彩票3d字谜如何处理地图的默认值以及存在哪些其他替代方法。

一个简单的问题

假设我们要编写一个通用函数,该函数接受一个集合并返回一个映射,该映射包含原始集合中与出现次数相关联的元素:

fun <T> countOccurrences(values: Collection<T>): Map<T, Int>

尽管(当然)在彩票3d字谜中有一种自然而简单的功能样式方式可以做到这一点,但我们还是要首先考虑一些迭代方法。让我们从下一个开始。

无默认值的迭代解决方案

fun <T> countOccurrences(values: Collection<T>): Map<T, Int> {
    val countMap = mutableMapOf<T, Int>()
    for (e in values) {
        val current = countMap[e]
        if (current == null) countMap[e] = 1 
        else countMap[e] = current + 1
    }
    return countMap
}

We can use a MutableMap for this algorithm. When iterating all values, we look into the map to see whether it has been seen 之前。 If so, we increment the counter; otherwise, we put an initial count of 1 into the map. A similar, but improved, solution 是 shown in the next part.

具有显式默认值的迭代解决方案

//sampleStart
countMap.putIfAbsent(e, 0)
// getValue, as an alternative to index operator, assures that a non-nullable type 是 returned
countMap[e] = countMap.getValue(e) + 1 

As an alternative to the previous solution, we can make use of putIfAbsent to ensure that the element 是 initialized with 0 so that we can safely increment the counter in the following line. What we do in this case 是 providing an explicit 默认 value. Another similar tool 是 getOrDefault:

countMap[e] = countMap.getOrDefault(e, 0) + 1

Providing explicit 默认s via putIfAbsent or getOrDefault leads to easy and understandable solutions, but we can do better.

具有隐式默认值的迭代解决方案

Similar to Python's 默认dict, 科特林 comes with a neat 延期 called MutableMap::withDefault and it looks like this:

fun <K, V> MutableMap<K, V>.withDefault(defaultValue: (key: K) -> V): MutableMap<K, V>

此扩展让我们为映射中没有关联值的键提供一个初始化程序。让我们在解决方案中使用它:

fun <T> countOccurrences(values: Collection<T>): Map<T, Int> {
    val countMap = mutableMapOf<T, Int>().withDefault { 0 }
    for (e in values) {
        countMap[e] = countMap.getValue(e) + 1
    }
    return countMap
}

因为我们不再需要在迭代中处理未知值,所以它进一步简化了代码。由于我们使用的是默认映射,因此我们可以安全地从中获取值,并在进行操作时增加计数器的数量。

重要的提示

There's one important thing you need to be aware of when using the withDefault 延期, which 是 part of its documentation:

[...]当原始地图不包含指定键的值,并且值为 通过[Map.getValue]函数获得 [...]

The 默认 value will only be provided if you use Map::getValue, which 是 not the case when accessing the map with index operators as you can observe 这里 (hit the run button):

fun main(){
    val map = mutableMapOf<String, Int>().withDefault { 0 }
    println(map["hello"])
    println(map.getValue("hello")) 
}

The reason for this 是 the contract of the Map interface, which says:

Returns the value corresponding to the given [key], or null if such a key 是 not present in the map.

Since 默认 maps want to fulfill this contract, they cannot return anything but null in the case of non-existent keys, which has been discussed in the 科特林论坛 之前。

让我们习惯

好吧,所以看到彩票3d字谜确实在地图中附带了默认值,这真是太棒了。但是,像上面示例中那样编写代码是不是习惯吗?我认为这取决于。使用彩票3d字谜出色的功能API(内置分组和计数功能),可以轻松解决大多数情况。尽管如此,了解替代方法还是一件好事,因为在某些情况下,您可能会选择采用迭代方法。让我为您提供我们的代码的简化版本:

fun <T> countOccurrences(values: Collection<T>): Map<T, Int> =
    mutableMapOf<T, Int>().withDefault { 0 }.apply {
        for (e in values) {
            put(e, getValue(e) + 1)
        }
    }

It still uses an explicit for loop but got simplified 通过 the use of apply which allows us to initialize the map in a single statement.

解决彩票3d字谜中的给定问题的方法有很多,但可能是最简单的一种 功能方法:

fun <T> countOccurrences(values: Collection<T>): Map<T, Int> =
    values.groupingBy { it }.eachCount()

结论

As shown in this little 文章, you can solve simple algorithms in many different ways using 科特林. Similar to Python, you can initialize a map with a 默认 value provider but need to be aware that the regular index operation access won't work the way you might expect. As documented, the getValue function has to be used. Since 科特林 comes with a very useful standard library, you want to consider using it as much as possible. This means that implementing common things like grouping or counting should, in most cases, not be implemented from scratch but rather be done with existing functionalities from the standard library.

一个想法“科特林中的默认地图

发表评论

您的电子邮件地址不会被公开。 必需的地方已做标记 *