it-roy-ru.com

Как обновить значение, учитывая ключ в хэш-карте Java?

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

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

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

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

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

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

837
Matthew Flaschen

Java 8 способ:

Вы можете использовать метод 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 и т.д.

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

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

46
oracleruiz

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

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

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

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

27
Christopher Bull

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

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

26
BalusC

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

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

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

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

Одноканальное решение:

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

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

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

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

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

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

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

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), то этот метод связывает его с данным значением и возвращает значение NULL, иначе возвращается текущее значение.

В случае если карта является общей для всех потоков, мы можем использовать ConcurrentHashMap и AtomicInteger . Из документа:

AtomicInteger - это значение типа int, которое может быть обновлено атомарно. AtomicInteger используется в таких приложениях, как атомарное увеличение счетчики, и не могут быть использованы в качестве замены для целого числа. Тем не мение, этот класс расширяет 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 значительно выше, за счет более высокого потребления пространства. Также проверьте это вопрос .

5
i_am_zero

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

map.replace(key, map.get(key) + 1);
4
Sergey Dirin

Используйте цикл 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 ....

}
2
VanHoutte

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

1
user1048218

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

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
   }
}
1
aayush nigam

Использовать встроенную функцию Java 8 '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);
    }
}
0
Rajesh Samson

Пытаться:

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

НОТА:

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

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

0
NARAYANAN.M
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 , поэтому вам нужно вынуть их, выполнить какой-то процесс, а затем вернуть его обратно. если у вас есть значение, которое не является типом данных Primitive, вам нужно только извлечь его, обработать, не нужно возвращать его обратно в hashmap.

0
Kreedz Zhen