Mapeie as chaves e os valores de um Mapa Scala


89

O MapLiketraço de Scala tem um método

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

Mas às vezes eu quero um tipo diferente:

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

Existe uma maneira simples de fazer isso que estou perdendo? Claro, isso pode ser feito com uma dobra.

Respostas:


164

mapmétodo itera por meio de todos os (key, value)pares. Você pode usá-lo assim:

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

val incM = m map {case (key, value) => (key, value + 1)}

8
Se você já tem uma função f : (A,B) => (A,C), pode simplesmente m.map(f.tupled). Funciona com, val f = (x: String, y: Int) => (x, y+1)mas estranhamente o repl reclama se eu definir fequivalentemente com def.
Dan Burton

2
o que a palavra-chave casealcança aqui?
Onipresente

@Omnipresente {case (key, value) => ...}é apenas uma correspondência de padrões neste caso. Em vez de fornecer uma função para a map, estou atribuindo a ele uma função parcial.
tenshi

Nota: casepermitirá que você coloque tipos em seu padrão, mas isso não é seguro, pois pode criar um erro de tempo de execução (porque é apenas uma correspondência de padrão). Enquanto isso, se você alterar a estrutura da coleção sob a mapfunção de forma que haja poucos ou muitos objetos para interpretar (key, value), mais uma vez, espero que você obtenha um erro de tempo de execução. :(
combinatorista

8

E quanto a 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 produz:

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

Isso pode ser empacotado no método do utilitário:

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
)

Não é o mesmo que MapLike#transform?
Hosam Aly


2

Com algum 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)

Eu gosto mais da solução de @ tenshi.


0

Você pode criar uma classe de utilitário:

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 não testado, mas deve funcionar de forma semelhante a este.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.