L'ajout d'une valeur en double à un HashSet / HashMap remplace-t-il la valeur précédente

137

Veuillez considérer le morceau de code ci-dessous:

HashSet hs = new HashSet();
hs.add("hi"); -- (1)
hs.add("hi"); -- (2)

hs.size()donnera 1 car HashSetn'autorise pas les doublons, donc un seul élément sera stocké.

Je veux savoir si nous ajoutons l'élément dupliqué, alors remplace-t-il l'élément précédent ou ne l'ajoute tout simplement pas?

Aussi, que se passera-t-il HashMappour le même cas?

Anand
la source

Réponses:

247

Dans le cas de HashMap, il remplace l'ancienne valeur par la nouvelle.

Dans le cas de HashSet, l'élément n'est pas inséré.

Keppil
la source
1
Vous ne savez pas ce que je manque, mais le code source semble indiquer le contraire? Je vois qu'ils ne vérifient pas le support HashMappour voir s'il keyexiste déjà avant de faire appel putau support map?
mystarrocks
10
@mystarrocks: La clé est l'élément du Set, et qui n'est jamais remplacé par l' put()opération.
Keppil
1
ah je comprends maintenant. J'ai compris que la clé est l'élément du Set, mais je viens de me rendre compte que put()cela ne remplacera que la valeur, pas la clé. Dans ce cas, c'est la même valeur mise à nouveau à côté de la clé, ce qui peut ou non être mieux que de vérifier si la clé existe et de mettre. De toute façon, je comprends comment cela fonctionne.
mystarrocks
Juste curieux, pourquoi HashMap et HashSet choisissent de l'être?
Helin Wang
@HelinWang: Je ne pense pas que ce soit prévu, je pense que c'est juste un effet d' HashSetêtre implémenté sous la forme d'un fichier HashMap. Difficile à savoir cependant, sauf si vous êtes l'un des développeurs des classes.
Keppil le
47

La première chose que vous devez savoir est qu'il HashSetagit comme un Set, ce qui signifie que vous ajoutez votre objet directement à HashSetet qu'il ne peut pas contenir de doublons. Vous ajoutez simplement votre valeur directement dans HashSet.

Cependant, HashMapc'est un Maptype. Cela signifie que chaque fois que vous ajoutez une entrée, vous ajoutez une paire clé-valeur.

Dans HashMapvous pouvez avoir des valeurs en double, mais pas des clés en double. Dans HashMapla nouvelle entrée remplacera l'ancienne. L'entrée la plus récente sera dans le HashMap.

Comprendre le lien entre HashMap et HashSet:

Rappelez-vous, HashMapne peut pas avoir de clés en double. Derrière la scène HashSetutilise un fichier HashMap.

Lorsque vous essayez d'ajouter un objet dans un HashSet, cette entrée est en fait stockée en tant que clé dans le HashMap- le même HashMapqui est utilisé derrière la scène de HashSet. Étant donné que ce sous-jacent a HashMapbesoin d'une paire clé-valeur, une valeur fictive est générée pour nous.

Maintenant, lorsque vous essayez d'insérer un autre objet dupliqué dans le même HashSet , il tentera à nouveau de l'insérer en tant que clé dans le HashMapcouché en dessous. Cependant, HashMapne prend pas en charge les doublons. Par conséquent, HashSetil en résultera toujours une seule valeur de ce type. En remarque, pour chaque clé dupliquée, puisque la valeur générée pour notre entrée dans HashSet est une valeur aléatoire / factice, la clé n'est pas du tout remplacée. il sera ignoré car la suppression de la clé et l'ajout de la même clé (la valeur fictive est la même) n'aurait aucun sens.

Résumé:

HashMapautorise la duplication values, mais paskeys . HashSetne peut pas contenir de doublons.

Pour savoir si l'ajout d'un objet est terminé avec succès ou non, vous pouvez vérifier la booleanvaleur renvoyée lorsque vous appelez .add() et voir si elle renvoie trueou false. S'il est retourné true, il a été inséré.

Jimmy
la source
HashMap allows duplicate valuesHashMap remplace l'ancienne valeur par la nouvelle.
Alex78191
20

La documentation est assez claire à ce sujet: HashSet.add ne remplace pas :

Ajoute l'élément spécifié à cet ensemble s'il n'est pas déjà présent. Plus formellement, ajoute l'élément spécifié e à cet ensemble si cet ensemble ne contient aucun élément e2 tel que (e == null? E2 == null: e.equals (e2)). Si cet ensemble contient déjà l'élément, l'appel laisse l'ensemble inchangé et retourne false.

Mais va remplacer:HashMap.put

Si la carte contenait auparavant un mappage pour la clé, l'ancienne valeur est remplacée.

pb2q
la source
4

C'est le cas de HashSet, il ne le remplace PAS.

À partir de la documentation:

http://docs.oracle.com/javase/6/docs/api/java/util/HashSet.html#add(E )

"Ajoute l'élément spécifié à cet ensemble s'il n'est pas déjà présent. Plus formellement, ajoute l'élément spécifié e à cet ensemble si cet ensemble ne contient aucun élément e2 tel que (e == null? E2 == null: e.equals ( e2)). Si cet ensemble contient déjà l'élément, l'appel laisse l'ensemble inchangé et renvoie false. "

Bob Provencher
la source
1

Corrigez-moi si je me trompe, mais ce que vous voulez dire, c'est qu'avec des chaînes, "Salut" == "Salut" ne sort pas toujours vrai (car ils ne sont pas nécessairement le même objet).

La raison pour laquelle vous obtenez une réponse de 1 est cependant que la machine virtuelle Java réutilisera les objets chaînes lorsque cela est possible. Dans ce cas, la JVM réutilise l'objet de chaîne et écrase ainsi l'élément dans le Hashmap / Hashset.

Mais ce comportement n'est pas garanti (car il peut s'agir d'un objet chaîne différent ayant la même valeur "Hi"). Le comportement que vous voyez est simplement dû à l'optimisation de la JVM.

Nick Rippe
la source
0

Vous devez d'abord vérifier la méthode put dans Hash map car HashSet est sauvegardé par HashMap

  1. Lorsque vous ajoutez une valeur en double, dites une chaîne "One" dans HashSet,
  2. Une entrée ("one", PRESENT) sera insérée dans Hashmap (pour toutes les valeurs ajoutées dans l'ensemble, la valeur sera "PRESENT" qui si de type Object)
  3. Hashmap ajoute l'entrée dans Map et renvoie la valeur, qui est dans ce cas "PRESENT" ou nulle si Entry n'est pas là.
  4. La méthode add de Hashset retourne alors true si la valeur renvoyée par Hashmap est égale à null sinon false, ce qui signifie qu'une entrée existe déjà ...
shiv
la source
0

Pour le dire différemment: lorsque vous insérez une paire clé-valeur dans un HashMap où la clé existe déjà (dans un sens, hashvalue () donne la même valeur et equal () est vrai, mais les deux objets peuvent toujours différer de plusieurs manières ), la clé n'est pas remplacée mais la valeur est écrasée. La clé est juste utilisée pour obtenir la valeur de hachage () et trouver la valeur dans la table avec elle. Puisque HashSet utilise les clés d'un HashMap et définit des valeurs arbitraires qui n'ont pas vraiment d'importance (pour l'utilisateur), les éléments de l'ensemble ne sont pas remplacés non plus.

Marco Rothley
la source
0

HashMapcontient essentiellement Entryce qui contient par la suite Key(Object)et. En Value(Object)interne HashSetsont HashMapet HashMapremplacent les valeurs comme certains d'entre vous l'ont déjà indiqué..mais cela remplace-t-il vraiment les clés ??? Non ... et c'est l'astuce ici. HashMapconserve sa valeur comme clé dans le sous-jacent HashMapet la valeur est juste un objet factice.Donc, si vous essayez de réinsérer la même valeur dans HashMap (clé dans la carte sous-jacente), elle remplace simplement la valeur factice et non la clé (valeur pour HashSet).

Regardez le code ci-dessous pour la classe HashSet:

public boolean  [More ...] add(E e) {

   return map.put(e, PRESENT)==null;
}

Ici, e est la valeur de HashSet mais la clé de la map sous-jacente et la clé n'est jamais remplacée. J'espère pouvoir dissiper la confusion.

Kunal Kumar
la source