我希望实现以下内容:
(_ : Map[K,Int]).mapKey(k, _ + 1)
mapKey
函数仅将第二个参数(Int => Int
)应用于k
下存储的值。标准库中有什么东西吗?如果不是,我打赌Scalaz中有一些东西。
当然我可以自己编写这个函数(m.updated(k,f(m(k))
),这样做很简单。但是我已经多次遇到这个问题,所以也许它已经完成了?
对于Scalaz,我想象下面的代码:
(m: Map[A,B]).project(k: A).map(f: B => B): Map[A,B]
答案 0 :(得分:3)
你当然可以添加
def changeForKey[A,B](a: A, fun: B => B): Tuple2[A, B] => Tuple2[A, B] = { kv =>
kv match {
case (`a`, b) => (a, fun(b))
case x => x
}
}
val theMap = Map('a -> 1, 'b -> 2)
theMap map changeForKey('a, (_: Int) + 1)
res0: scala.collection.immutable.Map[Symbol,Int] = Map('a -> 2, 'b -> 2)
但这会绕过关于内存重用和访问的任何优化。
我使用拉链为您提出的project
方法提供了一个相当冗长且效率低下的scalaz解决方案:
theMap.toStream.toZipper.flatMap(_.findZ(_._1 == 'a).flatMap(elem => elem.delete.map(_.insert((elem.focus._1, fun(elem.focus._2)))))).map(_.toStream.toMap)
或
(for {
z <- theMap.toStream.toZipper
elem <- z.findZ(_._1 == 'a)
z2 <- elem.delete
} yield z2.insert((elem.focus._1, fun(elem.focus._2)))).map(_.toStream.toMap)
可能没什么用处。我只是张贴参考。
答案 1 :(得分:3)
这是一种方式:
scala> val m = Map(2 -> 3, 5 -> 11)
m: scala.collection.immutable.Map[Int,Int] = Map(2 -> 3, 5 -> 11)
scala> m ++ (2, m.get(2).map(1 +)).sequence
res53: scala.collection.immutable.Map[Int,Int] = Map(2 -> 4, 5 -> 11)
scala> m ++ (9, m.get(9).map(1 +)).sequence
res54: scala.collection.immutable.Map[Int,Int] = Map(2 -> 3, 5 -> 11)
这是有效的,因为(A, Option[B]).sequence
提供Option[(A, B)]
。 (sequence
通常会将内部类型转换为内部。F[G[A]] => [G[F[A]]
,F : Traverse
和G : Applicative
。)
答案 2 :(得分:1)
你可以用它进行皮条客,以便它根据旧的地图创建一个新的地图:
class MapUtils[A, B](map: Map[A, B]) {
def mapValueAt(a: A)(f: (B) => B) = map.get(a) match {
case Some(b) => map + (a -> f(b))
case None => map
}
}
implicit def toMapUtils[A, B](map: Map[A, B]) = new MapUtils(map)
val m = Map(1 -> 1)
m.mapValueAt(1)(_ + 1)
// Map(1 -> 2)
m.mapValueAt(2)(_ + 1)
// Map(1 -> 1)