Предположим, у нас есть HashMap<String, Integer>
в Java.
Как обновить (увеличить) целочисленное значение строкового ключа для каждого существования найденной строки?
Можно было бы удалить и повторно ввести пару, но накладные расходы были бы проблемой.
Другим способом было бы просто поставить новую пару и заменить старую.
В последнем случае, что произойдет, если возникнет коллизия хеш-кода с новым ключом, который я пытаюсь вставить? Правильное поведение для хеш-таблицы будет состоять в том, чтобы назначить для нее другое место или составить список из нее в текущем сегменте.
getOrDefault
, например, используя:map.put(key, count.getOrDefault(key, 0) + 1);
Java 8 способ:
Вы можете использовать
computeIfPresent
метод и предоставить ему функцию отображения, которая будет вызываться для вычисления нового значения на основе существующего.Например,
В качестве альтернативы вы можете использовать
merge
метод, где 1 - это значение по умолчанию, а функция увеличивает существующее значение на 1:Кроме того, существует множество других полезных методов, таких , как
putIfAbsent
,getOrDefault
,forEach
, и т.д.источник
null
(скажемwords.put("hello", null);
), результат все ещеnull
не так,1
как я ожидал.compute()
вместо этого, он также будет обрабатыватьnull
значения..merge
Это мое решение сInteger::sum
.Метод
put
будет заменить значение существующего ключа и создаст его , если не существует.источник
nullPointer Exception
.null + 1
это, так как это попытается распаковатьnull
в целое число, чтобы сделать приращение.Упрощенный способ Java 8 :
При этом используется метод HashMap, который извлекает значение для ключа, но если ключ не может быть получен, он возвращает указанное значение по умолчанию (в данном случае «0»).
Это поддерживается в ядре Java: HashMap <K, V> getOrDefault (ключ объекта, V defaultValue)
источник
Замените
Integer
наAtomicInteger
и вызовите один из методовincrementAndGet
/getAndIncrement
.Альтернатива заключается в том, чтобы обернуть
int
в свой собственныйMutableInteger
класс, у которого естьincrement()
метод, вам остается только решить проблему безопасности потоков.источник
MutableInteger
лучше, так какAtomicInteger
используетvolatile
, у которого есть накладные расходы. Я бы использовалint[1]
вместоMutableInteger
.Одноканальное решение:
источник
Решение @ Мэтью является самым простым и в большинстве случаев будет работать достаточно хорошо.
Если вам нужна высокая производительность, AtomicInteger - более подходящее решение, например @BalusC.
Однако более быстрое решение (при условии, что безопасность потоков не является проблемой) заключается в использовании TObjectIntHashMap, который предоставляет метод приращения (ключ) и использует примитивы и меньшее количество объектов, чем при создании AtomicIntegers. например
источник
Вы можете увеличивать, как показано ниже, но вам нужно проверить существование, чтобы исключение NullPointerException
источник
Существует ли хэш (со значением 0) или он «помещен» на карту с первым шагом? Если он «помещен» в первый шаг, код должен выглядеть так:
источник
Может быть немного поздно, но вот мои два цента.
Если вы используете Java 8, вы можете использовать метод computeIfPresent . Если значение для указанного ключа присутствует и не равно нулю, то оно пытается вычислить новое сопоставление, учитывая ключ и его текущее сопоставленное значение.
Мы также можем использовать другой метод putIfAbsent для установки ключа. Если указанный ключ еще не связан со значением (или сопоставлен со значением NULL), этот метод связывает его с данным значением и возвращает значение NULL, иначе возвращается текущее значение.
В случае если карта является общей для всех потоков, мы можем использовать
ConcurrentHashMap
и AtomicInteger . Из документа:Мы можем использовать их как показано:
Следует обратить внимание на то, что мы вызываем
get
значение ключаB
и затем вызываемincrementAndGet()
его значение, которое, конечно же, является ключомAtomicInteger
. Мы можем оптимизировать его, так как методputIfAbsent
возвращает значение ключа, если оно уже присутствует:Кроме того, если мы планируем использовать AtomicLong, то в соответствии с документацией в условиях высокой конкуренции ожидаемая пропускная способность LongAdder значительно выше за счет более высокого потребления пространства. Также проверьте этот вопрос .
источник
Более чистое решение без NullPointerException:
источник
Поскольку я не могу комментировать несколько ответов из-за меньшей репутации, я опубликую решение, которое я применил.
источник
Используйте
for
цикл для увеличения индекса:источник
Здесь есть вводящие в заблуждение ответы на этот вопрос, которые подразумевают, что метод put Hashtable заменит существующее значение, если ключ существует, это не верно для Hashtable, а скорее для HashMap. См. Javadoc для HashMap http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html#put%28K,%20V%29
источник
или
Целочисленные значения - это примитивные типы данных http://cs.fit.edu/~ryan/java/language/java-data.html , поэтому вам нужно вынуть их, выполнить некоторый процесс, а затем вернуть его обратно. если у вас есть значение, которое не является типом данных Primitive, вам нужно только извлечь его, обработать, не нужно возвращать его обратно в хэш-карту.
источник
Пытаться:
НОТА:
Вы можете изменить либо ключ, либо значение в вашей хэш-карте, но вы не можете изменить оба одновременно.
источник
Используйте Java8 встроенную функцию 'computeIfPresent'
Пример:
источник