Самый эффективный способ увеличить значение Map в Java - PullRequest
324 голосов
/ 17 сентября 2008

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

Скажем, я создаю список частот слов, используя карту (возможно, HashMap), где каждый ключ представляет собой строку с подсчитываемым словом, а значение представляет собой целое число, которое увеличивается каждый раз, когда токен слова найдено.

В Perl увеличение такого значения было бы тривиально легко:

$map{$word}++;

Но в Java все гораздо сложнее. Вот как я сейчас это делаю:

int count = map.containsKey(word) ? map.get(word) : 0;
map.put(word, count + 1);

Что, конечно, зависит от функции автобокса в новых версиях Java. Интересно, можете ли вы предложить более эффективный способ увеличения такой стоимости? Существуют ли даже хорошие причины для отказа от использования среды Collections и использования чего-то еще?

Обновление: я проверил несколько ответов. Смотри ниже.

Ответы [ 27 ]

1 голос
/ 17 сентября 2008

Я бы использовал Apaz Lazy Map для инициализации значений 0 и использовал MutableIntegers из Apache Lang в качестве значений на этой карте.

Самой большой ценой является то, что в вашем методе нужно дважды найти карту. По моему вы должны сделать это только один раз. Просто получите значение (оно будет инициализировано, если оно отсутствует) и увеличьте его.

1 голос
/ 17 сентября 2008

Различные примитивные оболочки, например, Integer, являются неизменяемыми, поэтому на самом деле нет более краткого способа выполнить то, что вы просите , если только вы не можете сделать это с помощью чего-то вроде AtomicLong . Я могу дать это за минуту и ​​обновить. Кстати, Hashtable является частью Framework коллекций Framework .

1 голос
/ 17 сентября 2008

@ Вильмантас Баранаускас: Что касается этого ответа, я бы прокомментировал, если бы у меня были точки повторения, но у меня его нет. Я хотел бы отметить, что определенный здесь класс Counter НЕ является потокобезопасным, так как недостаточно просто синхронизировать inc () без синхронизации value (). Другие потоки, вызывающие value (), не гарантированно увидят значение, если с обновлением не было установлено отношение «происходит до».

1 голос
/ 25 марта 2019

Довольно просто, просто используйте встроенную функцию в Map.java, как следует

map.put(key, map.getOrDefault(key, 0) + 1);
1 голос
/ 13 мая 2009

В структуре TreeMap библиотеки *1003* функциональной библиотеки Java имеется метод update в последней магистральной линии:

public TreeMap<K, V> update(final K k, final F<V, V> f)

Пример использования:

import static fj.data.TreeMap.empty;
import static fj.function.Integers.add;
import static fj.pre.Ord.stringOrd;
import fj.data.TreeMap;

public class TreeMap_Update
  {public static void main(String[] a)
    {TreeMap<String, Integer> map = empty(stringOrd);
     map = map.set("foo", 1);
     map = map.update("foo", add.f(1));
     System.out.println(map.get("foo").some());}}

Эта программа печатает "2".

0 голосов
/ 03 февраля 2019

Надеюсь, я правильно понимаю ваш вопрос, я прихожу на Java из Python, чтобы сопереживать вашей борьбе.

если у вас есть

map.put(key, 1)

вы бы сделали

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

Надеюсь, это поможет!

0 голосов
/ 10 февраля 2018

Поскольку многие люди ищут в Java темы для ответов на Groovy, вот как вы можете это сделать в Groovy:

dev map = new HashMap<String, Integer>()
map.put("key1", 3)

map.merge("key1", 1) {a, b -> a + b}
map.merge("key2", 1) {a, b -> a + b}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...