Приращение целого числа в HashMap
Должен ли я вернуть объект, а затем добавить новый? Или я могу просто увеличивать?
Integer temp = myMap.get(key);
temp++;
myMap.put(key, temp);
нет способа сделать это (это не работает):
myMap.get(key)++;
Ответы
Ответ 1
Должен ли я вернуть объект, а затем добавить новый?
Пока вы используете класс оболочки Integer
yes, потому что он неизменен. Вместо этого вы можете использовать изменяемый класс-оболочку, даже тот, который имеет метод increment()
. Однако вы теряете возможность использовать autoboxing и autounboxing для значений.
Ответ 2
Вы можете использовать переменное целое число, такое как AtomicInteger.
Map<Key, AtomicInteger> myMap = new HashMap<Key, AtomicInteger>();
myMap.get(key).incrementAndGet();
Или вы можете использовать Trove4j, который поддерживает примитивы в коллекциях.
TObjectIntHashMap<Key> myMap;
myMap.increment(key);
Ответ 3
Это самый короткий код, который выполняет эту работу.
myMap.put(key, myMap.get(key) + 1)
Я думаю, что это не слишком долго.
Ответ 4
В Java 8 на Map
есть новые методы, которые вы можете использовать с lambdas для решения этой проблемы. Первая альтернатива, compute
:
a.compute(key, (k, v) -> v+1);
Обратите внимание, что это работает, только если хэш инициализирован для всех возможных ключей.
Если это не гарантировано, вы можете либо изменить приведенный выше код на:
a.compute(key, (k, v) -> v == null ? 1 : v + 1);
Или используйте метод merge
(который я бы предпочел):
a.merge(key, 1, (a, b) -> a + b);
Возможно, есть больше методов на основе лямбда, о которых я не знаю.
Ответ 5
Вы не можете напрямую увеличить его, потому что это immutable. Вы должны увеличить его и вернуть новый объект.
Здесь также вмешивается автоматический бокс. На самом деле то, что происходит, похоже на:
Integer i1 = getFromMap();
i1 = Integer.valueOf(++ i1.intValue());
Итак, здесь ваша ссылка указывает на новый объект. Вы должны вернуть этот объект на карту под тем же ключом.
Ответ 6
Поскольку Integer
неизменяемы, да, вы должны сделать это таким образом.
Если вы действительно хотите увеличить его напрямую, вам придется написать свой собственный изменяемый класс.
Ответ 7
Если вам нужно сделать это более двух раз, вы предпочтете создать крошечный класс, например:
public class MappedCounter {
private Map<String, Integer> map = new HashMap<String, Integer>();
public void addInt(String k, int v) {
if (!map.containsKey(k)) map.put(k, v);
else map.put(k, map.get(k) + v);
}
public int getInt(String k) {
return map.containsKey(k) ? map.get(k) : 0;
}
public Set<String> getKeys() {
return map.keySet();
}
}
Ответ 8
Прежде всего: будьте в курсе unboxing: temp от типа Integer. Но операция ++ реализована для int. Поэтому temp распаковывается для ввода int. Это означает, что если temp null, вы выполняете исключение NullPointerException.
И вы должны сделать это, как вы записали в свой первый блок кода.
Ответ 9
Я использую приведенный ниже код, и он работает, но вначале вам нужно определить BiFunction
, описывающий, что операция увеличивается на 1.
public static Map<String, Integer> strInt = new HashMap<String, Integer>();
public static void main(String[] args) {
BiFunction<Integer, Integer, Integer> bi = (x,y) -> {
if(x == null)
return y;
return x+y;
};
strInt.put("abc", 0);
strInt.merge("abc", 1, bi);
strInt.merge("abc", 1, bi);
strInt.merge("abc", 1, bi);
strInt.merge("abcd", 1, bi);
System.out.println(strInt.get("abc"));
System.out.println(strInt.get("abcd"));
}
вывод
3
1
Ответ 10
Просто для полноты в Java 8 существует longAdder, который приносит некоторые преимущества по сравнению с AtomicInteger (http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/LongAdder.html)
final Map<WhatEver, LongAdder> result = new HashMap<>();
result.get(WhatEver).increment();
Ответ 11
Это должно работать
// If the key you want to add does not exist then add it as a new key
// And make the value 1
if (map.get(key) == null) {
map.put(key, 1);
} else {
// If the key does exist then replace the key value with it's
// Original value plus one
map.put(key, map.get(key) + 1);
}