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.

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

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
)

Ist das nicht dasselbe wie MapLike#transform?
Hosam Aly


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.


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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.