如果键存在或不插入新元素,则向 Scala 映射中的元素添加数字的好方法
Nice way to add number to element in Scala map if key exists or insert new element it not
我知道几个类似的问题。他们没有帮助我 - 如果没有现有密钥,代码将无法工作。
我只需要一些好的方法来附加带有值的 Map,将其添加到现有键(如果它确实存在)或作为新键(如果 map 不包含适当的键)。
以下代码有效,但我不喜欢它:
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)
}
有什么更好的吗?
当前的 Scala 版本是 2.10.4,我目前无法切换到 2.11。
可变映射不是 100% 限制但首选。
例如,similar question,但我还需要考虑不存在的密钥的情况,该密钥未在此处说明。至少我们应该理解 a.get(key)
可以是 None
或者添加一些更好的方法。 |+|
是个好主意,但我想保留基本的 Scala 2。10.x。
您可以为此目的创建自己的函数:
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)
最短的方法:
a += a.get(key).map(x => key -> (x + 5)).getOrElse("k5" -> 200)
总的来说:
a += a.get(k).map(f).map(k -> _).getOrElse(kv)
如果您的字典是不可变的,则相同:
m + m.get(k).map(f).map(k -> _).getOrElse(kv)
所以我看不出有任何理由在这里使用可变集合。
如果您不喜欢所有这些 Option.map
事情:
m + (if (m.contains(k)) k -> f(m(k)) else kv)
请注意,有整个 class 种可能的变化:
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
那么,为什么它不是标准函数? IMO,因为所有变体仍然可以作为单线实现。如果您想要具有所有功能的库,可以将其实现为一行代码,您知道,它是 Scalaz :)。
P.S。如果您还想知道为什么没有 "update(d) if persist" 函数 - 请参阅@Rex Kerr 的回答 here
一个比较明确的方法:
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
不过,我完全不鼓励使用可变集合。最好将内部可变状态保持为包含不可变字段的变量。
这是因为一个简单的规则,你不应该暴露你的内部状态,除非它是完全必要的,如果你这样做,你应该尽可能减少可能产生的潜在副作用。
如果公开可变状态的引用,任何其他参与者都可以更改它的值,从而失去引用透明度。 所有对可变集合的引用都非常长且难以使用,这并非偶然。这是开发者给你的消息
不足为奇,代码仍然保持不变,在地图实例化时有一些微小的变化。
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
Scala 2.13 introduced updatedWith
method 这似乎是根据键的存在有条件地更新地图的最惯用的方法。
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)
也可以使用它删除值:
val a2 = a.updatedWith("k2") {
case Some(5) => None
case v => v
}
println(a2) // Map(k1 -> 1)
摘自Scala Standard Library reference:
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 (Some
if there is current mapping, None
if not).
If the remapping function returns Some(v)
, the mapping is updated with the new value v
. If the remapping function returns None
, 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.
对于你的可变地图,你可以这样做:
val a = collection.mutable.Map(("k1" -> 1), ("k2" -> 5))
val key = "k1"
a.update(key, a.getOrElse(key, 0) + 5)
a // val res1: scala.collection.mutable.Map[String,Int] = HashMap(k1 -> 6, k2 -> 5)
我知道几个类似的问题。他们没有帮助我 - 如果没有现有密钥,代码将无法工作。
我只需要一些好的方法来附加带有值的 Map,将其添加到现有键(如果它确实存在)或作为新键(如果 map 不包含适当的键)。
以下代码有效,但我不喜欢它:
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)
}
有什么更好的吗? 当前的 Scala 版本是 2.10.4,我目前无法切换到 2.11。 可变映射不是 100% 限制但首选。
例如,similar question,但我还需要考虑不存在的密钥的情况,该密钥未在此处说明。至少我们应该理解 a.get(key)
可以是 None
或者添加一些更好的方法。 |+|
是个好主意,但我想保留基本的 Scala 2。10.x。
您可以为此目的创建自己的函数:
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)
最短的方法:
a += a.get(key).map(x => key -> (x + 5)).getOrElse("k5" -> 200)
总的来说:
a += a.get(k).map(f).map(k -> _).getOrElse(kv)
如果您的字典是不可变的,则相同:
m + m.get(k).map(f).map(k -> _).getOrElse(kv)
所以我看不出有任何理由在这里使用可变集合。
如果您不喜欢所有这些 Option.map
事情:
m + (if (m.contains(k)) k -> f(m(k)) else kv)
请注意,有整个 class 种可能的变化:
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
那么,为什么它不是标准函数? IMO,因为所有变体仍然可以作为单线实现。如果您想要具有所有功能的库,可以将其实现为一行代码,您知道,它是 Scalaz :)。
P.S。如果您还想知道为什么没有 "update(d) if persist" 函数 - 请参阅@Rex Kerr 的回答 here
一个比较明确的方法:
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
不过,我完全不鼓励使用可变集合。最好将内部可变状态保持为包含不可变字段的变量。
这是因为一个简单的规则,你不应该暴露你的内部状态,除非它是完全必要的,如果你这样做,你应该尽可能减少可能产生的潜在副作用。
如果公开可变状态的引用,任何其他参与者都可以更改它的值,从而失去引用透明度。 所有对可变集合的引用都非常长且难以使用,这并非偶然。这是开发者给你的消息
不足为奇,代码仍然保持不变,在地图实例化时有一些微小的变化。
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
Scala 2.13 introduced updatedWith
method 这似乎是根据键的存在有条件地更新地图的最惯用的方法。
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)
也可以使用它删除值:
val a2 = a.updatedWith("k2") {
case Some(5) => None
case v => v
}
println(a2) // Map(k1 -> 1)
摘自Scala Standard Library reference:
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 (
Some
if there is current mapping,None
if 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.
对于你的可变地图,你可以这样做:
val a = collection.mutable.Map(("k1" -> 1), ("k2" -> 5))
val key = "k1"
a.update(key, a.getOrElse(key, 0) + 5)
a // val res1: scala.collection.mutable.Map[String,Int] = HashMap(k1 -> 6, k2 -> 5)