Asignar claves y valores de un mapa Scala

89

El MapLikerasgo de Scala tiene un método

mapValues [C] (f: (B) ⇒ C): Map[A, C] 

Pero a veces quiero un tipo diferente:

mapKeysAndValues [C] (f: (A, B) ⇒ C): Map[A, C] 

¿Hay una forma sencilla de hacer esto que me falta? Por supuesto, esto se puede hacer con un pliegue.

Alexey Romanov
fuente

Respuestas:

166

mapEl método itera a través de todos los (key, value)pares. Puedes usarlo así:

val m = Map("a" -> 1, "b" -> 2)

val incM = m map {case (key, value) => (key, value + 1)}
tenshi
fuente
8
Si ya tiene una función f : (A,B) => (A,C), simplemente puede hacerlo m.map(f.tupled). Funciona con, val f = (x: String, y: Int) => (x, y+1)pero extrañamente la respuesta se queja si defino de manera fequivalente def.
Dan Burton
2
¿Qué logra la palabra clave caseaquí?
Omnipresente
@Omnipresent {case (key, value) => ...}es solo una coincidencia de patrones en este caso. En lugar de proporcionar una función a a map, le doy una función parcial.
tenshi
Nota: casele permitirá poner tipos en su patrón, pero esto no es seguro ya que podría crear un error en tiempo de ejecución (porque es solo una coincidencia de patrón). Mientras tanto, si alguna vez cambia la estructura de la colección debajo de la mapfunción de modo que haya muy pocos o demasiados objetos para interpretar (key, value), una vez más, espero que obtenga un error de tiempo de ejecución. :(
combinatorist
8

¿Qué pasa con este código:

val m = Map(1 -> "one", 2 -> "two")
def f(k: Int, v: String) = k + "-" + v
m map {case (k, v) => (k, f(k, v))}

Que produce:

 Map(1 -> 1-one, 2 -> 2-two)

Esto se puede empaquetar en el método de utilidad:

def mapKeysAndValues[A,B,C](input: Map[A,B], fun: (A, B) => C) = 
  input map {case(k,v) => (k, fun(k, v))}

Uso:

mapKeysAndValues(
  Map(1 -> "one", 2 -> "two"), 
  (k: Int, v: String) => k + "-" + v
)
Tomasz Nurkiewicz
fuente
¿No es esto lo mismo que MapLike#transform?
Hosam Aly
5
m map (t => (t._1, t._2 + 1))

m map (t => t._1 -> t._2 + 1)
Grigory Kislin
fuente
2

Con algo de Scalaz:

scala> def fst[A, B] = (x: (A, B)) => x._1
fst: [A, B]=> (A, B) => A

scala> Map(1 -> "Lorem", 2 -> "Ipsum").map(fst &&& Function.tupled(_.toString + _))
res1: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> 1Lorem, 2 -> 2Ipsum)

Me gusta más la solución de @ tenshi.

desaparecido faktor
fuente
0

Podría crear una clase de utilidad:

class MyMapLike[K,V](m:MapLike[K,V,_]){
 def mapKeysAndValues[R](f: (K, V) => R)={
   m.map{case (k,v)=> f(k,v)}
 } 
}
object MyMapLike{
 implicit def maplike2mymaplike[K,V](ml:MapLike[K,V,_]):MyMapLike[K,V]=new MyMapLike(m)

}

import MyMapLike._
Map(1 -> "one", 2 -> "two").mapKeysAndValues(k,v=>v*k)

Código no probado, pero debería funcionar de alguna manera similar.

Alex
fuente