Question Comment mettre à jour une valeur, donné une clé dans un hashmap java?


Supposons que nous ayons un HashMap<String, Integer> en Java.

Comment mettre à jour (incrémenter) la valeur entière de la chaîne de caractères pour chaque existence de la chaîne que je trouve?

On pourrait enlever et réentrer la paire, mais les frais généraux seraient une préoccupation.
Une autre façon serait de simplement mettre la nouvelle paire et l'ancienne serait remplacée.

Dans ce dernier cas, que se passe-t-il s'il y a une collision avec une nouvelle clé que j'essaie d'insérer? Le comportement correct d'une table de hachage consiste à lui affecter un emplacement différent ou à en faire une liste dans le compartiment en cours.


476
2017-11-11 18:34


origine


Réponses:


map.put(key, map.get(key) + 1);

ça devrait aller. Il mettra à jour la valeur pour le mappage existant. Notez que cela utilise la boxe automatique.


744
2017-11-11 18:39



Java 8 way:

Vous pouvez utiliser computeIfPresent méthode et lui fournir une fonction de mappage, qui sera appelée pour calculer une nouvelle valeur basée sur celle existante.

Par exemple,

Map<String, Integer> words = new HashMap<>();
words.put("hello", 3);
words.put("world", 4);
words.computeIfPresent("hello", (k, v) -> v + 1);
System.out.println(words.get("hello"));

Alternativement, vous pourriez utiliser merge méthode, où 1 est la valeur par défaut et la fonction incrémente la valeur existante de 1:

words.merge("hello", 1, Integer::sum);

En outre, il existe un tas d'autres méthodes utiles, telles que putIfAbsent, getOrDefault, forEach, etc.


67
2017-09-11 09:15



hashmap.put(key, hashmap.get(key) + 1);

La méthode put volonté remplacer la valeur d'une clé existante et la créera si elle n'existe pas.


43
2017-11-03 16:35



Remplacer Integer par AtomicInteger et appeler l'un des incrementAndGet/getAndIncrement méthodes à ce sujet.

Une alternative consiste à envelopper un int dans votre propre MutableInteger classe qui a un increment() méthode, vous avez seulement un problème de sécurité à résoudre pour le moment.


25
2017-11-11 18:37



@ La solution de Matthew est la plus simple et fonctionnera assez bien dans la plupart des cas.

Si vous avez besoin de hautes performances, AtomicInteger est une meilleure solution ala @BalusC.

Cependant, une solution plus rapide (à condition que la sécurité des threads ne soit pas un problème) consiste à utiliser TObjectIntHashMap qui fournit une méthode increment (key) et utilise des primitives et moins d'objets que la création d'AtomicIntegers. par exemple.

TObjectIntHashMap<String> map = new TObjectIntHashMap<String>()
map.increment("aaa");

16
2017-11-11 18:56



Le simplifié Java 8 façon:

map.put(key, map.getOrDefault(key, 0) + 1);

Cela utilise la méthode de HashMap qui récupère la valeur pour une clé, mais si la clé ne peut pas être récupérée, elle renvoie la valeur par défaut spécifiée (dans ce cas un '0').

Ceci est pris en charge dans le noyau Java: HashMap <K, V> getOrDefault (Clé de l'objet, V defaultValue)


15
2018-06-08 14:48



Une solution en ligne:

map.put(key, map.containsKey(key) ? map.get(key) + 1 : 1);

13
2017-12-06 18:10



Vous pouvez incrémenter comme ci-dessous mais vous devez vérifier l'existence de sorte qu'une exception NullPointerException ne soit pas levée

if(!map.containsKey(key)) {
 p.put(key,1);
}
else {
 p.put(key, map.getKey()+1);
}

11
2017-08-09 18:57



Le hash existe-t-il (avec 0 comme valeur) ou est-il "mis" sur la carte lors du premier incrément? S'il est "mis" sur le premier incrément, le code devrait ressembler à:

if (hashmap.containsKey(key)) {
    hashmap.put(key, hashmap.get(key)+1);
} else { 
    hashmap.put(key,1);
}

8
2018-03-03 20:29



C'est peut-être un peu tard, mais voici mes deux cents.

Si vous utilisez Java 8, vous pouvez utiliser computeIfPresent méthode. Si la valeur de la clé spécifiée est présente et non nulle, elle tente de calculer un nouveau mappage en fonction de la clé et de sa valeur mappée actuelle.

final Map<String,Integer> map1 = new HashMap<>();
map1.put("A",0);
map1.put("B",0);
map1.computeIfPresent("B",(k,v)->v+1);  //[A=0, B=1]

Nous pouvons également utiliser une autre méthode putIfAbsent mettre une clé. Si la clé spécifiée n'est pas déjà associée à une valeur (ou mappée à null), cette méthode l'associe à la valeur donnée et renvoie null, sinon renvoie la valeur actuelle.

Si la carte est partagée entre les threads, nous pouvons utiliser ConcurrentHashMap et AtomicInteger. De la doc:

Un AtomicInteger est une valeur int pouvant être mise à jour de manière atomique. Un   AtomicInteger est utilisé dans des applications telles que l'incrémentation atomique   compteurs, et ne peuvent pas être utilisés en remplacement d'un nombre entier. cependant,   cette classe étend Numéro pour permettre un accès uniforme par les outils et   des utilitaires qui traitent des classes numériques.

Nous pouvons les utiliser comme indiqué:

final Map<String,AtomicInteger> map2 = new ConcurrentHashMap<>();
map2.putIfAbsent("A",new AtomicInteger(0));
map2.putIfAbsent("B",new AtomicInteger(0)); //[A=0, B=0]
map2.get("B").incrementAndGet();    //[A=0, B=1]

Un point à observer est que nous invoquons get pour obtenir la valeur de clé B puis invoquer incrementAndGet() sur sa valeur qui est bien sûr AtomicInteger. Nous pouvons l'optimiser en tant que méthode putIfAbsent renvoie la valeur de la clé si elle est déjà présente:

map2.putIfAbsent("B",new AtomicInteger(0)).incrementAndGet();//[A=0, B=2]

Sur une note de côté si nous prévoyons d'utiliser AtomicLong puis, selon la documentation sous haute contention attendu débit de LongAdder est significativement plus élevé, au détriment de l'augmentation de la consommation d'espace. Vérifiez également ceci question.


5
2018-05-24 07:51



La solution de nettoyage sans NullPointerException est la suivante:

map.replace(key, map.get(key) + 1);

2
2018-01-22 07:14