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.

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)}

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
)

¿No es esto lo mismo que MapLike#transform?
Hosam Aly


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.


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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.