Ordnen Sie sowohl Schlüssel als auch Werte einer Scala-Karte zu

88

Scalas MapLikeMerkmal hat eine Methode

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

Aber ich möchte manchmal einen anderen Typ:

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

Gibt es eine einfache Möglichkeit, die mir fehlt? Dies kann natürlich mit einer Falte erfolgen.

Alexey Romanov
quelle

Antworten:

163

mapMethode iteriert durch alle (key, value)Paare. Sie können es so verwenden:

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

val incM = m map {case (key, value) => (key, value + 1)}
Tenshi
quelle
8
Wenn Sie bereits eine Funktion haben f : (A,B) => (A,C), können Sie einfach m.map(f.tupled). Funktioniert mit, val f = (x: String, y: Int) => (x, y+1)aber seltsamerweise beschwert sich die Antwort, wenn ich fgleichwertig mit definiere def.
Dan Burton
2
Was leistet das Keyword casehier?
Allgegenwärtig
@Omnipresent {case (key, value) => ...}ist in diesem Fall nur ein Mustervergleich. Anstatt a eine Funktion zu geben map, gebe ich ihr eine Teilfunktion.
Tenshi
Hinweis: caseSie können Typen in das Muster einfügen, dies ist jedoch nicht sicher, da dies zu einem Laufzeitfehler führen kann (da es sich nur um eine Musterübereinstimmung handelt). Wenn Sie in der Zwischenzeit die Struktur der Sammlung unter der mapFunktion so ändern , dass zu wenige oder zu viele Objekte zum Interpretieren vorhanden sind (key, value), wird erneut ein Laufzeitfehler erwartet. :(
Kombinator
8

Was ist mit diesem Code:

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

Welches produziert:

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

Dies kann in die Dienstprogrammmethode gepackt werden:

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

Verwendung:

mapKeysAndValues(
  Map(1 -> "one", 2 -> "two"), 
  (k: Int, v: String) => k + "-" + v
)
Tomasz Nurkiewicz
quelle
Ist das nicht dasselbe wie MapLike#transform?
Hosam Aly
5
m map (t => (t._1, t._2 + 1))

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

Mit etwas 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)

Ich mag die Lösung von @ tenshi besser.

fehlender Faktor
quelle
0

Sie können eine Dienstprogrammklasse erstellen:

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)

Code nicht getestet, aber es sollte irgendwie ähnlich funktionieren.

Alex
quelle