Хранение пары примитивов в Java HashMap - PullRequest
6 голосов
/ 24 мая 2009

У меня есть список файлов. Я хотел бы просканировать и вести подсчет количества файлов с одинаковым размером. проблема связана с размером файла, который, как мы знаем, длинный, будет принимать только объект, а не примитив. Поэтому, используя new Long(filesize), я поместил его в hashmap. вместо того, чтобы получить пару (filesize, count), я получил список (filesize, 1) из-за того, что каждый Long obj уникален.

Как мне создать аккумулятор?

Любое решение для 1.4.2?

Ответы [ 6 ]

15 голосов
/ 24 мая 2009

Вы просто делаете это так:

Map<Long, Integer> count = new HashMap<Long, Integer>();
for (File file : files) {
  long size = file.getTotalSpace();
  Integer n = count.get(size);
  if (n == null) {
    count.put(size, 1);
  } else {
    count.put(size, n + 1);
  }
}

Существует некоторая автобокс и здесь происходит распаковка.

6 голосов
/ 24 мая 2009

Вместо использования new Long(size), вы должны использовать Long.valueOf(size). это возвратит ту же самую длинную ссылку, которая кешируется внутри, и также должна повысить производительность (не то, что она будет видна, если вы не выполните миллионы этих new Long() операций).

пс. работает только для Java 1.5 или выше

4 голосов
/ 25 мая 2009

Можно использовать Trove для хранения пар (long, int) - TLongIntHashMap

3 голосов
/ 24 мая 2009

или вы можете использовать AtomicInteger в качестве изменяемого целого числа.

Map<Long, AtomicInteger> count = new HashMap<Long, AtomicInteger>();
for (File file : files) {
  long size = file.length(); // getTotalSpace() get the space consumed (e.g. a multiple of 8K) rather the actual file size.
  AtomicInteger n = count.get(size);
  if (n == null) {
    count.put(size, new AtomicInteger(1));
  } else {
    n.getAndIncrement();
  }
}
1 голос
/ 24 мая 2009

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

Вы упомянули:

... из-за того, что каждый длинный объект уникален.

Я не думаю, что это проблема. Хотя это может быть правдой в зависимости от того, как вы создаете экземпляры Longs, это не должно мешать HashMaps вести себя так, как вы хотите. Пока два ключевых объекта возвращают одно и то же значение hashCode (), а метод equals () говорит, что они равны, ваш HashMap не будет создавать для него другую запись. Фактически, у вас не должно быть возможности видеть «список (filesize, 1)» с теми же значениями размера файла (если вы не написали свой собственный Long и не смогли правильно реализовать hashCode () / equals ()).

Тем не менее, код Cletus должен работать, если вы используете Java 5 или выше, если вы используете Java 1.4 или ниже, вам нужно будет либо сделать свой собственный бокс / распаковку вручную, либо заглянуть в Коллекции Apache Commons . Вот пример Cletus до Java 5:

Map count = new HashMap();
for (Iterator filesIter = files.iterator(); filesIter.hasNext();) {
  File file = (File)filesIter.next();
  long size = file.getTotalSpace();
  Integer n = count.get(size);
  if (n == null) {
    count.put(size, Integer.valueOf(1));
  } else {
    count.put(size, Integer.valueOf(n.intValue() + 1));
  }
}
1 голос
/ 24 мая 2009

Расширение того, что написал Клетус.

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

Map<Long, Collection<File>> count = new HashMap<Long, Collection<File>>();
for (File file : files) {
long size = file.getTotalSpace();
Collection<File> c = count.get(size);
if (c == null) {
    c = new ArrayList<File>(); //or whatever collection you feel comfortable with
    count.put(size, c);
}
    c.add(file);
} 

тогда вы можете получить количество файлов с помощью c.size () и вы можете легко перебрать все файлы с этим номером без необходимости повторного запуска этой процедуры.

...