Как обновить значение, учитывая ключ в hashmap?

Предположим, что в Java есть HashMap<String, Integer>.

Как обновить (увеличить) целочисленное значение строкового ключа для каждого существования строки, которую я нахожу?

Можно удалить и повторно ввести пару, но накладные расходы будут проблемой.
Другой способ - просто поместить новую пару, а старый будет заменен.

В последнем случае, что произойдет, если есть столкновение hashcode с новым ключом, который я пытаюсь вставить? Правильное поведение хэш-таблицы было бы назначением для него другого места или составлением списка из текущего ковша.

Ответ 1

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

должно быть хорошо. Он обновит значение для существующего сопоставления. Обратите внимание, что в этом случае используется автоматический бокс.

Ответ 2

Java 8-way:

Вы можете использовать метод computeIfPresent и предоставить ему функцию сопоставления, которая будет вызываться для вычисления нового значения на основе существующего.

Например,

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"));

Альтернативно, вы можете использовать метод merge, где 1 - значение по умолчанию, а функция увеличивает существующее значение на 1:

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

Кроме того, существует множество других полезных методов, таких как putIfAbsent, getOrDefault, forEach и т.д.

Ответ 3

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

Метод put заменит значение существующего ключа и создаст его, если его не существует.

Ответ 4

Упрощенный способ Java 8:

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

В этом случае используется метод HashMap, который извлекает значение для ключа, но если ключ не может быть восстановлен, он возвращает указанное значение по умолчанию (в этом случае значение "0" ).

Это поддерживается в ядре Java: HashMap < K, V > getOrDefault (ключ объекта, V defaultValue)

Ответ 5

Замените Integer на AtomicInteger и вызовите один из методов incrementAndGet/getAndIncrement на нем.

Альтернативой является обертка int в вашем собственном классе MutableInteger, который имеет метод increment(), у вас еще есть проблема, связанная с потоками.

Ответ 6

Решение @Matthew является самым простым и будет работать достаточно хорошо в большинстве случаев.

Если вам нужна высокая производительность, AtomicInteger - лучшее решение ala @BalusC.

Однако более быстрое решение (при условии, что безопасность потоков не является проблемой) заключается в использовании TObjectIntHashMap, который предоставляет метод приращения (ключа) и использует примитивы и меньше объектов, чем создание AtomicIntegers. например.

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

Ответ 7

Однострочное решение:

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

Ответ 8

Вы можете увеличивать, как показано ниже, но вам нужно проверить существование, чтобы исключить NullPointerException.

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

Ответ 9

Существует ли хэш (с 0 в качестве значения) или он "помещен" на карту при первом приращении? Если он "ставится" на первый шаг, код должен выглядеть так:

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

Ответ 10

Это может быть немного поздно, но вот мои два цента.

Если вы используете Java 8, вы можете использовать метод computeIfPresent. Если значение для указанного ключа присутствует и не равно null, оно пытается вычислить новое сопоставление с учетом ключа и текущего отображаемого значения.

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]

Мы также можем использовать другой метод putIfAbsent, чтобы поместить ключ. Если указанный ключ еще не связан со значением (или сопоставлен с нулем), то этот метод связывает его с заданным значением и возвращает значение null, иначе возвращает текущее значение.

Если карта распределяется по потокам, мы можем использовать ConcurrentHashMap и AtomicInteger. Из документа:

An AtomicInteger - значение int, которое может быть обновлено атомарно. AtomicInteger используется в приложениях, таких как атомарно увеличивающиеся счетчиков и не может использоваться в качестве замены для Integer. Однако, этот класс расширяет Number, чтобы обеспечить равномерный доступ с помощью инструментов и утилиты, которые работают с численными классами.

Мы можем использовать их, как показано:

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]

Одна точка для наблюдения заключается в том, что мы вызываем get, чтобы получить значение для ключа B, а затем вызывая incrementAndGet() по его значению, которое, конечно, AtomicInteger. Мы можем оптимизировать его, так как метод putIfAbsent возвращает значение для ключа, если оно уже присутствует:

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

На стороне примечания, если мы планируем использовать AtomicLong, то согласно документации при высокой конкуренции ожидаемая пропускная способность LongAdder значительно выше, за счет более высокого потребления пространства. Также проверьте этот question.

Ответ 11

Более чистое решение без NullPointerException:

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

Ответ 12

Используйте цикл for для увеличения индекса:

for (int i =0; i<5; i++){
    HashMap<String, Integer> map = new HashMap<String, Integer>();
    map.put("beer", 100);

    int beer = map.get("beer")+i;
    System.out.println("beer " + beer);
    System.out ....

}

Ответ 13

Поскольку я не могу прокомментировать несколько ответов из-за меньшей репутации, я отправлю решение, которое я применил.

for(String key : someArray)
{
   if(hashMap.containsKey(key)//will check if a particular key exist or not 
   {
      hashMap.put(hashMap.get(key),value+1);// increment the value by 1 to an already existing key
   }
   else
   {
      hashMap.put(key,value);// make a new entry into the hashmap
   }
}

Ответ 14

Здесь есть вводящие в заблуждение ответы, которые предполагают, что метод Hashtable put заменит существующее значение, если ключ существует, это неверно для Hashtable, а скорее для HashMap. См. Javadoc для HashMap http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html#put%28K,%20V%29

Ответ 15

Try:

HashMap hm=new HashMap<String ,Double >();

Примечание:

String->give the new value; //THIS IS THE KEY
else
Double->pass new value; //THIS IS THE VALUE

Вы можете изменить либо ключ, либо значение в вашем хэш-карте, но вы не можете изменить оба одновременно.

Ответ 16

Integer i = map.get(key);
if(i == null)
   i = (aValue)
map.put(key, i + 1);

или

Integer i = map.get(key);
map.put(key, i == null ? newValue : i + 1);

Целое - это примитивные типы данных http://cs.fit.edu/~ryan/java/language/java-data.html, поэтому вам нужно вытащить его, сделать какой-то процесс, а затем вернуть его обратно. если у вас есть значение, которое не является примитивным типом данных, вам нужно только его вынуть, обработать, не нужно возвращать его в хэш-карту.

Ответ 17

Используйте Java8 встроенную функцию 'computeIfPresent'

Пример:

public class ExampleToUpdateMapValue {

    public static void main(String[] args) {
        Map<String,String> bookAuthors = new TreeMap<>();
        bookAuthors.put("Genesis","Moses");
        bookAuthors.put("Joshua","Joshua");
        bookAuthors.put("Judges","Samuel");

        System.out.println("---------------------Before----------------------");
        bookAuthors.entrySet().stream().forEach(System.out::println);
        // To update the existing value using Java 8
        bookAuthors.computeIfPresent("Judges", (k,v) -> v = "Samuel/Nathan/Gad");

        System.out.println("---------------------After----------------------");
        bookAuthors.entrySet().stream().forEach(System.out::println);
    }
}