如果键存在或不插入新元素,则在 Scala 映射中向元素添加数字的好方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28387048/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Nice way to add number to element in Scala map if key exists or insert new element it not
提问by Roman Nikitchenko
I know about couple of similar questions. They don't help me - code does not work if there is no existing key.
我知道几个类似的问题。他们对我没有帮助——如果没有现有的密钥,代码就不起作用。
I need just some nice approach to append Map with value adding it to existing key (if it does exist) or putting as NEW key (if map does not contain appropriate key).
我只需要一些不错的方法来附加 Map 并将其添加到现有键(如果它确实存在)或作为新键(如果 map 不包含适当的键)的值。
Following code works but I don't like it:
以下代码有效,但我不喜欢它:
val a = collection.mutable.Map(("k1" -> 1), ("k2" -> 5))
val key = "k1"
val elem = a.get(key)
if (elem == None) {
a += ("k5" -> 200)
} else {
a.update(key, elem.get + 5)
}
Any point to better one? Current Scala version is 2.10.4 and I cannot currently switch to 2.11. Mutable map is not 100% limitation but preferred.
有什么更好的吗?当前的 Scala 版本是 2.10.4,我目前无法切换到 2.11。可变映射不是 100% 限制,而是首选。
Here is, for example, similar questionbut I also need to account case of non-existing key which is not accounted there. At least we should understand a.get(key)could be Noneor add some better approach. Good idea was |+|but I'd like to keep basic Scala 2.10.x.
例如,这是类似的问题,但我还需要考虑在那里没有考虑的不存在的密钥的情况。至少我们应该明白a.get(key)可以None或添加一些更好的方法。好主意,|+|但我想保留基本的 Scala 2.10.x。
采纳答案by Jean Logeart
You can create you own function for that purpose:
您可以为此创建自己的函数:
def addOrUpdate[K, V](m: collection.mutable.Map[K, V], k: K, kv: (K, V),
f: V => V) {
m.get(k) match {
case Some(e) => m.update(k, f(e))
case None => m += kv
}
}
addOrUpdate(a, "k1", "k5" -> 200, (v: Int) => v + 5)
回答by dk14
The shortest way to do that:
做到这一点的最短方法:
a += a.get(key).map(x => key -> (x + 5)).getOrElse("k5" -> 200)
In general:
一般来说:
a += a.get(k).map(f).map(k -> _).getOrElse(kv)
Same if your dictionary is immutable:
如果您的字典是不可变的,则相同:
m + m.get(k).map(f).map(k -> _).getOrElse(kv)
so I don't see any reason to use mutable collection here.
所以我看不出有任何理由在这里使用可变集合。
If you don't like all these Option.mapthings:
如果你不喜欢所有这些Option.map东西:
m + (if (m.contains(k)) k -> f(m(k)) else kv)
Note, that there is a whole class of possible variations:
请注意,有一整类可能的变化:
k1 -> f(m(k1)) else k2 -> v2 //original
k1 -> f(m(k1)) else k1 -> v2
k1 -> f(m(k2)) else k2 -> v2
k1 -> f(m(k2)) else k1 -> v2
k2 -> v2 else k1 -> f(m(k1))
k1 -> v2 else k1 -> f(m(k1))
k2 -> v2 else k1 -> f(m(k2))
k1 -> v2 else k1 -> f(m(k2))
... //v2 may also be a function from some key's value
So, Why it's not a standard function? IMO, because all variations still can be implemented as one-liners. If you want library with all functions, that can be implemented as one-liners, you know, it's Scalaz :).
那么,为什么它不是标准功能?IMO,因为所有变体仍然可以作为单线实施。如果您想要具有所有功能的库,可以将其实现为单行程序,您知道,它是 Scalaz :)。
P.S. If yu also wonder why there is no "update(d) if persist" function - see @Rex Kerr 's answer here
PS如果宇还奇怪为什么没有“更新(d)如果坚持”功能-见@Rex克尔的答案在这里
回答by Maximiliano Felice
One somewhat clear way to do this:
一种比较清楚的方法来做到这一点:
val a = collection.mutable.Map[String, Int]() withDefault insertNewValue
def insertNewValue(key: String): Int =
a += key -> getValueForKey(key)
a(key)
}
def getValueForKey(key: String): Int = key.length
Still, I totally discourage the use of mutable collections. It's preferable to keep internal mutable state as variables holding immutable fields.
不过,我完全不鼓励使用可变集合。最好将内部可变状态保持为包含不可变字段的变量。
This is because of a simple rule, you shouldn't expose your internal state unless it's totally necessary, and if you do, you should diminish as much as possible the potential side effects that may produce.
这是因为一个简单的规则,除非完全有必要,否则您不应该公开您的内部状态,如果您这样做,您应该尽可能减少可能产生的潜在副作用。
If you expose a reference of a mutable state, any other actor can change it's values, thus losing referential transparency. It's not by chance that all references to mutable collections are quite long, and difficult to use. That's a developer's message for you
如果公开可变状态的引用,任何其他参与者都可以更改它的值,从而失去引用透明度。对可变集合的所有引用都非常长且难以使用,这并非偶然。这是给您的开发人员消息
Not surprisingly, the code still remains the same, with some minimal changes at the map instantiation.
毫不奇怪,代码仍然保持不变,只是在地图实例化上有一些细微的变化。
var a = Map[String, Int]() withDefault insertNewValue
def insertNewValue(key: String): Int = {
a += key -> getValueForKey(key)
a(key)
}
def getValueForKey(key: String): Int = key.length
回答by Vilius
Scala 2.13 introduced updatedWithmethodwhich seems to be the most idiomatic way to update a map conditionally on the existence of the key.
Scala 2.13 引入了updatedWith方法,这似乎是根据键的存在条件更新映射的最惯用的方法。
val a = Map(("k1" -> 1), ("k2" -> 5))
val a1 = a.updatedWith("k1") {
case Some(v) => Some(v + 5)
case None => Some(200)
}
println(a1) // Map(k1 -> 6, k2 -> 5)
One may also remove values using it:
也可以使用它删除值:
val a2 = a.updatedWith("k2") {
case Some(5) => None
case v => v
}
println(a2) // Map(k1 -> 1)
An excerpt from the Scala Standard Library reference:
Scala 标准库参考的摘录:
def updatedWith[V1 >: V](key: K)(remappingFunction: (Option[V]) => Option[V1]): Map[K, V1]Update a mapping for the specified key and its current optionally-mapped value (
Someif there is current mapping,Noneif not).If the remapping function returns
Some(v), the mapping is updated with the new valuev. If the remapping function returnsNone, the mapping is removed (or remains absent if initially absent). If the function itself throws an exception, the exception is rethrown, and the current mapping is left unchanged.
def updatedWith[V1 >: V](key: K)(remappingFunction: (Option[V]) => Option[V1]): Map[K, V1]更新指定键及其当前可选映射值的映射(
Some如果有当前映射,None如果没有)。如果重映射函数返回
Some(v),则使用新值更新映射v。如果重映射函数返回None,则删除映射(如果最初不存在,则保持不存在)。如果函数本身抛出异常,则重新抛出异常,当前映射保持不变。

