2009-05-24 14 views
6

Mam listę plików. Chciałbym przejrzeć i zachować liczbę plików o tym samym rozmiarze. problemem jest rozmiar pliku, który jest długi, ponieważ wiemy, że hashmap przyjmie tylko obiekt, a nie prymitywę. Więc używając new Long(filesize), umieściłem go w mapie mieszającej. zamiast uzyskać parę (wielkość pliku, liczba), mam listę (rozmiar pliku, 1) ze względu na to, że każdy długi obiekt jest unikalny.Przechowywanie pary prymitywów w Java HashMap

jak mam budować ten akumulator?

dowolne rozwiązanie dla wersji 1.4.2?

Odpowiedz

15

po prostu zrobić to w ten sposób:

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

jest jakaś auto-boxing i unboxing tu dzieje.

3

lub możesz użyć AtomicInteger jako zmienną całkowitą.

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(); 
    } 
} 
7

Zamiast new Long(size), należy użyć Long.valueOf(size). który zwróci ten sam Długi odnośnik, który jest wewnętrznie buforowany, i powinien również zwiększyć wydajność (nie, że będzie widoczny, chyba że wykonasz miliony tych operacji new Long()).

ps. działa tylko dla java 1.5 lub nowszy

+0

AFAICT w 1,6 Long.valueOf tylko buforuje 256 tęskni które przekraczają zera . Wszystkie wartości większe niż 128 nie będą buforowane, podobnie wartości poniżej -127. –

+0

dla wersji 1.6 (nie 1.5 lub niższej) można zmienić to zachowanie, ustawiając -XX: AutoBoxCacheMax = 1000 (patrz http://www.javaspecialists.eu/archive/Issue191.html) - jeśli aplikacja zostanie spowolniona przez takie operacje już wtedy podejrzewam, że jest tam jakiś problem algorytmiczny ... – Chii

1

Poszerzenie tego, co napisał cletus.

Jego rozwiązanie jest w porządku, z wyjątkiem tego, że przechowuje tylko wszystkie napotkane pliki i liczbę plików o tym rozmiarze. Jeśli kiedykolwiek będziesz chciał wiedzieć, które pliki są, ta struktura danych będzie dla ciebie bezużyteczna, więc nie sądzę, aby rozwiązanie typu cletus było kompletne. Zamiast tego chciałbym zrobić

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

następnie można uzyskać liczbę plików z c.size() i można iterację wszystkich plików z tej liczby łatwo bez konieczności ponownego uruchomienia tej procedury.

+1

Zapominasz wstawić listę do mapy. –

+0

dzięki! haha, często zapominam o tych rzeczach i wracają, żeby mnie ugryźć w dupę. – ldog

+0

użyteczne rozwiązanie, chociaż rozwiązanie typu cletus jest bliższe temu, czego potrzebuję. – zeroin23

1

Myślę, że jest w tym więcej i będziemy potrzebować więcej szczegółów od Ciebie. Zakładam, że wiesz, że jest zdecydowanie więcej niż jeden plik o danym rozmiarze, w przeciwnym razie najpierw sprawdziłbym, czy tak jest. Dla wszystkich wiesz, masz po prostu wiele plików o unikalnych rozmiarach plików.

można wymienić:

... z uwagi na fakt, że każdy z długim obj jest wyjątkowy.

Nie sądzę, że to jest problem. Chociaż może to być prawda w zależności od tego, w jaki sposób tworzysz instancje Longów, nie powinno to uniemożliwiać zachowywania się HashMaps tak, jak chcesz. Dopóki dwa kluczowe obiekty zwracają tę samą wartość hashCode(), a metoda equals() mówi, że są one równe, twoja HashMap nie utworzy dla niej innego wpisu. W rzeczywistości nie powinno być możliwe wyświetlenie "listy (filesize, 1)" z tymi samymi wartościami rozmiaru pliku (chyba że napisałeś własny Long i nie udało się poprawnie zaimplementować hashCode()/equals()).

To powiedziawszy, kod Cletusa powinien działać, jeśli używasz Java 5 lub wyższej, jeśli używasz Java 1.4 lub niższej, musisz ręcznie zrobić własne boksowanie/rozpakowywanie lub zajrzeć do Apache Commons Collections .Oto wersja pre-Java 5 przykład Cletus':

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)); 
    } 
} 
+0

stało się na maszynie jdk1.4.2 ... – zeroin23