web-dev-qa-db-fra.com

Comment implémenter la carte avec une opération par défaut dans Scala

class DefaultListMap[A, B <: List[B]] extends HashMap[A, B] {
    override def default(key: A) = List[B]() 
  }

Je ne veux pas créer de carte A -> List[B]. Dans mon cas, c'est Long -> List[String] mais lorsque j'obtiens une clé de la carte qui n'a pas de valeur, je voudrais créer List vide au lieu de Exception être jeté. J'ai essayé différentes combinaisons mais je ne sais pas comment faire passer le code ci-dessus au compilateur.

Merci d'avance.

45
Lukasz

Pourquoi ne pas utiliser withDefaultValue (valeur)?

scala> val m = Map[Int, List[String]]().withDefaultValue(List())
m: scala.collection.immutable.Map[Int,List[String]] = Map()

scala> m(123)
res1: List[String] = List()
106
Ilya Klyuchnikov

Plutôt que d'utiliser apply pour accéder à la carte, vous pouvez toujours utiliser get, qui renvoie Option[V] puis getOrElse:

map.get(k) getOrElse Nil

Une grande fonctionnalité de la bibliothèque de programmation fonctionnelle scalaz est l'opérateur unaire ~, ce qui signifie "ou zéro", tant que le type de valeur a un "zéro" défini (ce que List fait, le zéro étant Nil bien sûr). Le code devient alors:

~map.get(k)

Ceci est doublement utile car la même syntaxe fonctionne là où (par exemple) vos valeurs sont Int, Double etc (tout ce qui contient une classe de caractères Zero).


Il y a eu beaucoup de débats sur la liste de diffusion scala sur l'utilisation de Map.withDefault en raison de la façon dont cela se comporte alors en ce qui concerne la méthode isDefinedAt, entre autres. J'ai tendance à m'en éloigner pour cette raison.

23
oxbow_lakes

Il existe une méthode withDefaultValue sur Map:

scala> val myMap = Map(1 -> List(10), 2 -> List(20, 200)).withDefaultValue(Nil)
myMap: scala.collection.immutable.Map[Int,List[Int]] = Map((1,List(10)), (2,List(20, 200)))

scala> myMap(2)
res0: List[Int] = List(20, 200)

scala> myMap(3)
res1: List[Int] = List()
11
kassens

Pourquoi voulez-vous manipuler une carte alors qu'elle a déjà une méthode pour cela?

val m = Map(1L->List("a","b"), 3L->List("x","y","z"))  
println(m.getOrElse(1L, List("c"))) //--> List(a, b)
println(m.getOrElse(2L, List("y"))) //--> List(y)
3
Landei

withDefault peut également être utilisé.

/** The same map with a given default function.
 *  Note: `get`, `contains`, `iterator`, `keys`, etc are not affected
 *  by `withDefault`.
 *
 *  Invoking transformer methods (e.g. `map`) will not preserve the default value.
 *
 *  @param d     the function mapping keys to values, used for non-present keys
 *  @return      a wrapper of the map with a default value
 */
 def withDefault[B1 >: B](d: A => B1): immutable.Map[A, B1]

Exemple:

scala> def intToString(i: Int) = s"Integer $i"
intToString: (i: Int)String

scala> val x = Map[Int, String]().withDefault(intToString)
x: scala.collection.immutable.Map[Int,String] = Map()

scala> x(1)
res5: String = Integer 1

scala> x(2)
res6: String = Integer 2

J'espère que cela t'aides.

2
tharindu_DG