Mappa sia le chiavi che i valori di una Scala Map


89

Il MapLiketratto di Scala ha un metodo

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

Ma a volte ne voglio un tipo diverso:

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

C'è un modo semplice per farlo che mi manca? Naturalmente, questo può essere fatto con una piega.

Risposte:


164

mapmetodo itera sebbene tutte le (key, value)coppie. Puoi usarlo in questo modo:

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

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

8
Se hai già una funzione f : (A,B) => (A,C), puoi semplicemente m.map(f.tupled). Funziona con val f = (x: String, y: Int) => (x, y+1)ma stranamente il sostituto si lamenta se definisco in modo fequivalente con def.
Dan Burton

2
che cosa ottiene la parola chiave casequi?
Onnipresente

@Omnipresent {case (key, value) => ...}è solo un pattern-matching in questo caso. Invece di fornire una funzione a a map, gli do una funzione parziale.
tenshi

Nota: caseti consentirà di inserire i tipi nel suo pattern, ma questo non è sicuro in quanto potrebbe creare un errore di runtime (perché è solo una corrispondenza di pattern). Nel frattempo, se modifichi la struttura della raccolta sotto la mapfunzione in modo che ci siano troppo pochi o troppi oggetti da interpretare come (key, value), allora ancora una volta, mi aspetto che riceverai un errore di runtime. :(
combinatore

8

Che dire di questo codice:

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

Che produce:

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

Questo può essere impacchettato nel metodo di utilità:

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

Utilizzo:

mapKeysAndValues(
  Map(1 -> "one", 2 -> "two"), 
  (k: Int, v: String) => k + "-" + v
)

Non è lo stesso di MapLike#transform?
Hosam Aly


2

Con un po 'di 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)

Mi piace di più la soluzione di @ tenshi.


0

Potresti creare una classe di utilità:

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)

Codice non testato ma dovrebbe funzionare in qualche modo in modo simile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.