11
votes

Cartes par défaut imbriquées dans Scala

J'essaie de construire des cartes imbriquées dans Scala, où la carte extérieure et intérieure utilise la méthode "withDefaultValue". Par exemple, les éléments suivants: xxx

de sorte que la carte, lorsqu'elle est adressée par les touches appropriées, me donne ce que j'ai mis en place. Cependant, la carte elle-même apparaît vide! Même M.Size retourne 0 dans cet exemple. Quelqu'un peut-il expliquer ce qui se passe ici?


0 commentaires

5 Réponses :


2
votes

withDefaultValue est utilisé pour renvoyer une valeur lorsque la clé n'a pas été trouvée. Il ne peuplie pas la carte. Donc, vous mappez de rester vide. Un peu comme en utilisant getorelse (a, b) b est fourni par withdefaulardvalue . .


2 commentaires

Bien sûr, mais quand j'appelle m (1) (2) = 5, cela devrait placer la valeur 5 sur la carte. Pourquoi, alors la carte apparaît-elle vide après cette "mise à jour ()"?


@nomad, je suis assez intrigué par le comportement intéressant ici, mais tout fait en réalité beaucoup de sens. m est toujours vide après cette mise à jour, car ce que vous avez mis à jour était pas m; Vous avez mis à jour une des valeurs par défaut de M. C'est-à-dire que vous avez mis à jour la carte qui est référencée par m (1) jusqu'à ce que m (1) ait une valeur réelle. Puisque vous avez changé la taille de que carte, et que vous n'avez jamais mis à jour les paires de la valeur de clé m> m> m> m> m est toujours vide, dans la mesure où elle est concernée.



0
votes

Ce que vous voyez est l'effet que vous avez créé une seule carte carte [int, int] code> Il s'agit de la valeur par défaut lorsque la touche ne figure pas dans la carte extérieure.

scala> val m = HashMap.empty[(Int, Int), Int].withDefaultValue(3)
m: scala.collection.mutable.Map[(Int, Int),Int] = Map()

scala> m((1, 2))
res0: Int = 3

scala> m((1, 2)) = 5

scala> m((1, 2))
res3: Int = 5

scala> m
res4: scala.collection.mutable.Map[(Int, Int),Int] = Map((1,2) -> 5)


0 commentaires

16
votes

Réponse courte

Ce n'est certainement pas un bug. p>

réponse longue h2>

Le comportement de withDefaultValue code> est de stocker une valeur par défaut (dans votre cas, une carte mutable) à l'intérieur de la carte à renvoyer dans le cas où elles ne existent pas. Ce n'est pas la même chose qu'une valeur insérée em> dans la carte lorsqu'elle est introuvable. P>

Regardons de près ce qui se passe. Il sera plus facile de comprendre si nous tirons la carte par défaut comme une variable distincte afin que nous puissions inspecter est à volonté; Appelons-le défaut code> p> xxx pré>

donc par défaut code> est une carte mutable (qui a sa propre valeur par défaut). Maintenant, nous pouvons créer m code> et donner par défaut code> comme valeur par défaut. P> xxx pré>

maintenant chaque fois que m Code> est accessible avec une clé manquante, il retournera par défaut code>. Notez que c'est le même comportement que vous avez exactement que vous avez parce que withdefaulardValue code> est défini comme suit: p> xxx pré>

remarque que c'est D: B code> et non d: => b code>, il ne créera donc pas une nouvelle carte chaque fois que la valeur par défaut est accessible; Il retournera le même objet exact, ce que nous avons appelé par défaut code>. p>

Voyons donc ce qui se passe: p>

m2 // Map(1 -> Map(2 -> 6))


1 commentaires

Je l'obtiens maintenant; La ventilation a beaucoup aidé. C'est intéressant à quel point mon préjugé initial sur la façon dont je pensais que la fonction devrait me empêcher de voir ce qui se passait réellement.



1
votes

J'avais juste exactement le même problème et je suis heureux de trouver la réponse de DHG. Depuis la frappe GetorelseUpdate tout le temps n'est pas très concis, j'ai proposé cette petite extension de l'idée que je veux partager: Vous pouvez déclarer une classe qui utilise getorelseeupdate comme comportement par défaut pour l'opérateur ():

var map = new DefaultDict[Int, DefaultDict[Int, Int]](
  key => new DefaultDict(key => 3))
map(1)(2) = 5


1 commentaires

S'il vous plaît ne faites pas. Merci.



0
votes

Je sais que c'est un peu tard mais je viens de voir le poste pendant que j'essayais de résoudre le même problème.
L'API est probablement différente de la version 2012, mais vous pouvez utiliser withdefault à la place que withdefaultValue .
La différence est que withdefault prend une fonction en tant que paramètre, qui est exécuté chaque fois qu'une clé manquée est demandée;)


0 commentaires