Angenommen, wir haben eine HashMap<String, Integer>
in Java.
Wie aktualisiere (inkrementiere) ich den Integer-Wert des String-Schlüssels für jede Existenz des gefundenen Strings?
Man könnte das Paar entfernen und erneut eingeben, aber der Aufwand wäre ein Problem.
Ein anderer Weg wäre, einfach das neue Paar zu setzen und das alte zu ersetzen.
Was passiert im letzteren Fall, wenn eine Hashcode-Kollision mit einem neuen Schlüssel auftritt, den ich einzufügen versuche? Das richtige Verhalten für eine Hashtabelle wäre, ihr einen anderen Ort zuzuweisen oder eine Liste daraus im aktuellen Bucket zu erstellen.
getOrDefault
zum Beispiel verwendet wird:map.put(key, count.getOrDefault(key, 0) + 1);
Java 8 Weg:
Sie können die
computeIfPresent
Methode verwenden und ihr eine Zuordnungsfunktion zuweisen, die aufgerufen wird, um einen neuen Wert basierend auf dem vorhandenen zu berechnen.Zum Beispiel,
Alternativ können Sie eine
merge
Methode verwenden, bei der 1 der Standardwert ist und die Funktion den vorhandenen Wert um 1 erhöht:Darüber hinaus gibt es eine Reihe von anderen nützlichen Methoden, wie
putIfAbsent
,getOrDefault
,forEach
usw.quelle
null
(sagen wirwords.put("hello", null);
) ist. Das Ergebnis ist immer nochnull
nicht so,1
wie ich es erwarten würde.compute()
stattdessen auchnull
Werte verarbeiten..merge
meine Lösung mitInteger::sum
.Das Verfahren
put
wird ersetzen Sie den Wert eines vorhandenen Schlüssels und wird es schaffen , wenn nicht vorhanden ist .quelle
nullPointer Exception
.null + 1
Dies ist nicht möglich, da hierdurch versucht wird, dienull
in eine Ganzzahl zu entpacken , um das Inkrement durchzuführen .Der vereinfachte Java 8- Weg:
Dies verwendet die Methode von HashMap, die den Wert für einen Schlüssel abruft. Wenn der Schlüssel jedoch nicht abgerufen werden kann, wird der angegebene Standardwert zurückgegeben (in diesem Fall eine '0').
Dies wird in Java unterstützt: HashMap <K, V> getOrDefault (Objektschlüssel, V defaultValue)
quelle
Ersetzen Sie
Integer
durchAtomicInteger
und rufen Sie eine derincrementAndGet
/getAndIncrement
Methoden auf.Eine Alternative besteht darin, eine
int
in Ihre eigeneMutableInteger
Klasseincrement()
einzubinden, die eine Methode hat. Sie müssen nur noch ein Sicherheitsbedenken lösen.quelle
MutableInteger
ist besser alsAtomicInteger
Verwendungenvolatile
, die Overhead haben. Ich würdeint[1]
anstelle von verwendenMutableInteger
.Einzeilige Lösung:
quelle
@ Matthews Lösung ist die einfachste und funktioniert in den meisten Fällen gut genug.
Wenn Sie eine hohe Leistung benötigen, ist AtomicInteger eine bessere Lösung als @BalusC.
Eine schnellere Lösung (vorausgesetzt, die Thread-Sicherheit ist kein Problem) ist die Verwendung von TObjectIntHashMap, die eine Inkrementierungsmethode (Schlüsselmethode) bereitstellt und Grundelemente und weniger Objekte verwendet als das Erstellen von AtomicIntegern. z.B
quelle
Sie können wie unten inkrementieren, müssen jedoch die Existenz überprüfen, damit keine NullPointerException ausgelöst wird
quelle
Existiert der Hash (mit 0 als Wert) oder wird er beim ersten Inkrement auf die Karte "gesetzt"? Wenn es beim ersten Inkrement "gesetzt" wird, sollte der Code folgendermaßen aussehen:
quelle
Es mag etwas spät sein, aber hier sind meine zwei Cent.
Wenn Sie Java 8 verwenden, können Sie die computeIfPresent- Methode verwenden. Wenn der Wert für den angegebenen Schlüssel vorhanden und nicht null ist, wird versucht, eine neue Zuordnung unter Berücksichtigung des Schlüssels und seines aktuellen zugeordneten Werts zu berechnen.
Wir können auch eine andere Methode putIfAbsent verwenden , um einen Schlüssel zu setzen. Wenn der angegebene Schlüssel noch keinem Wert zugeordnet ist (oder null zugeordnet ist), ordnet diese Methode ihn dem angegebenen Wert zu und gibt null zurück, andernfalls wird der aktuelle Wert zurückgegeben.
Falls die Karte über Threads gemeinsam genutzt , dann können wir nutzen
ConcurrentHashMap
und Atomicinteger . Aus dem Dokument:Wir können sie wie gezeigt verwenden:
Ein zu beachtender Punkt ist, dass wir aufrufen
get
, um den Wert für den Schlüssel zu erhalten,B
und dannincrementAndGet()
dessen Wert aufrufen , was natürlich der Fall istAtomicInteger
. Wir können es optimieren, da die MethodeputIfAbsent
den Wert für den Schlüssel zurückgibt, falls dieser bereits vorhanden ist:Nebenbei bemerkt, wenn wir vorhaben, AtomicLong zu verwenden, ist der erwartete Durchsatz von LongAdder gemäß der Dokumentation unter hohen Konflikten auf Kosten eines höheren Platzverbrauchs erheblich höher. Überprüfen Sie auch diese Frage .
quelle
Die sauberere Lösung ohne NullPointerException lautet:
quelle
Da ich aufgrund des geringeren Ansehens einige Antworten nicht kommentieren kann, werde ich eine Lösung veröffentlichen, die ich angewendet habe.
quelle
Verwenden Sie eine
for
Schleife, um den Index zu erhöhen:quelle
Es gibt hier irreführende Antworten auf diese Frage, die implizieren, dass die Hashtable-Put-Methode den vorhandenen Wert ersetzt, wenn der Schlüssel vorhanden ist. Dies gilt nicht für Hashtable, sondern für HashMap. Siehe Javadoc für HashMap http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html#put%28K,%20V%29
quelle
oder
Ganzzahl ist der primitive Datentyp http://cs.fit.edu/~ryan/java/language/java-data.html . Sie müssen ihn also herausnehmen, einen Prozess ausführen und dann zurücksetzen. Wenn Sie einen Wert haben, der kein primitiver Datentyp ist, müssen Sie ihn nur herausnehmen, verarbeiten und nicht wieder in die Hashmap einfügen.
quelle
Versuchen:
HINWEIS:
Sie können entweder den Schlüssel oder den Wert in Ihrer Hashmap ändern, aber Sie können nicht beide gleichzeitig ändern.
quelle
Verwenden Sie die in Java8 integrierte Funktion 'computeIfPresent'.
Beispiel:
quelle