Mapper à la fois les clés et les valeurs d'une carte Scala


89

Le MapLiketrait de Scala a une méthode

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

Mais je veux parfois un type différent:

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

Existe-t-il un moyen simple de le faire qui me manque? Bien sûr, cela peut être fait avec un pli.

Réponses:


164

mapLa méthode itère sur toutes les (key, value)paires. Vous pouvez l'utiliser comme ceci:

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

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

8
Si vous avez déjà une fonction f : (A,B) => (A,C), vous pouvez simplement m.map(f.tupled). Fonctionne avec val f = (x: String, y: Int) => (x, y+1)mais étrangement le repl se plaint si je définis de manière féquivalente avec def.
Dan Burton

2
à quoi sert le mot-clé caseici?
Omniprésent le

@Omnipresent {case (key, value) => ...}est juste un pattern-matching dans ce cas. Au lieu de fournir une fonction à a map, je lui donne une fonction partielle.
tenshi le

Remarque: casevous permettra de mettre des types dans son modèle, mais ce n'est pas sûr car cela pourrait créer une erreur d'exécution (car c'est juste une correspondance de modèle). En attendant, si jamais vous changez la structure de la collection sous la mapfonction afin qu'il y ait trop peu ou trop d'objets à interpréter comme (key, value), alors encore une fois, je suppose que vous obtiendrez une erreur d'exécution. :(
combinatorist le

8

Qu'en est-il de ce 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))}

Ce qui produit:

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

Cela peut être emballé dans la méthode utilitaire:

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

Usage:

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

N'est-ce pas la même chose que MapLike#transform?
Hosam Aly


2

Avec quelques 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)

J'aime mieux la solution de @ tenshi.


0

Vous pouvez créer une classe utilitaire:

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 non testé mais il devrait fonctionner d'une manière ou d'une autre comme ça.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.