Hatékony szófrekvencia-számológép Java-ban
1. Áttekintés
Ebben az oktatóanyagban bemutatjuk a szószámláló Java alkalmazásának különféle módjait.
2. Ellenmegvalósítások
Kezdjük azzal, hogy egyszerűen kiszámoljuk a tömb szavainak számát:
statikus karakterlánc [] COUNTRY_NAMES = {"Kína", "Ausztrália", "India", "USA", "Szovjetunió", "Egyesült Királyság", "Kína", "Franciaország", "Lengyelország", "Ausztria", "India" , "USA", "Egyiptom", "Kína"};
Ha hatalmas fájlokat akarunk feldolgozni, akkor az itt leírt egyéb lehetőségeket kell választanunk.
2.1. Térkép Val vel Egész számok
Az egyik legegyszerűbb megoldás az a Térkép, tárolja a szavakat kulcsként, és az előfordulások számát értékként:
Map counterMap = új HashMap (); for (String country: COUNTRY_NAMES) {counterMap.compute (ország, (k, v) -> v == null? 1: v + 1); } assertEquals (3, counterMap.get ("Kína"). intValue ()); assertEquals (2, counterMap.get ("India"). intValue ());
Egyszerűen használtuk TérképPraktikus kiszámít metódus, amely növeli a számlálót, vagy inicializálja 1-vel, ha a kulcs nincs meg.
Azonban, a számláló létrehozásának ez a módszere nem hatékony Egész szám megváltoztathatatlan, ezért minden alkalommal, amikor növeljük a számlálót, létrehozunk egy újat Egész szám tárgy.
2.2. Stream API
Használjuk ki a Java 8 Stream API-t párhuzamosan Patakok, és a csoportosításBy() gyűjtő:
@Test public void whenMapWithLambdaAndWrapperCounter_runsSuccessfully () {Map counterMap = new HashMap (); Stream.of (COUNTRY_NAMES) .collect (Collectors.groupingBy (k -> k, () -> counterMap, Collectors.counting ()); assertEquals (3, counterMap.get ("China"). IntValue ()); assertEquals (2, counterMap.get ("India"). IntValue ());}
Hasonlóképpen használhatnánk a parallelStream:
@Test public void whenMapWithLambdaAndWrapperCounter_runsSuccessfully () {Map counterMap = new HashMap (); Stream.of (COUNTRY_NAMES) .parallel () .collect (Collectors.groupingBy (k -> k, () -> counterMap, Collectors.counting ()); assertEquals (3, counterMap.get ("China"). IntValue ( assertEquals (2, counterMap.get ("India"). intValue ());}
2.3. Térkép Egy valamivel Egész szám Sor
Ezután használjuk a Térkép amely egy pultot teker egy Egész szám értékként használt tömb:
@Test public void whenMapWithPrimitiveArrayCounter_runsSuccessfully () {Map counterMap = new HashMap (); counterWithPrimitiveArray (counterMap); assertEquals (3, counterMap.get ("Kína") [0]); assertEquals (2, counterMap.get ("India") [0]); } private void counterWithPrimitiveArray (Map counterMap) {for (Karakterlánc ország: COUNTRY_NAMES) {counterMap.compute (ország, (k, v) -> v == null? új int [] {0}: v) [0] ++ ; }}
Vegye figyelembe, hogyan hoztunk létre egy egyszerű HashMap val vel int tömbök mint értékeket.
Ban,-ben counterWithPrimitiveArray módszerrel, miközben a tömb minden egyes értékét iteráljuk, mi:
- meghívni a kap a counterMap az országnév kulcsként történő átadásával
- ellenőrizze, hogy van-e már kulcs vagy sem. Ha a bejegyzés már jelen van, létrehozunk egy új példányt a primitív egész tömbből, egyetlen „1” -nel. Ha a bejegyzés hiányzik, akkor növeljük a tömbben található ellenértéket
Ez a módszer jobb, mint a burkoló megvalósítása - mivel kevesebb tárgyat hoz létre.
2.4. Térkép Val,-vel MutableInteger
Ezután hozzunk létre egy burkolóobjektumot, amely beágyaz egy primitív egész számlálót az alábbiak szerint:
privát statikus osztály MutableInteger {int count = 1; public void increment () {ez.szám ++; } // getter és setter}
Lássuk, hogyan használhatjuk számlálóként a fenti osztályt:
@Test public void whenMapWithMutableIntegerCounter_runsSuccessfully () {Map counterMap = new HashMap (); mapWithMutableInteger (counterMap); assertEquals (3, counterMap.get ("Kína"). getCount ()); assertEquals (2, counterMap.get ("India"). getCount ()); } private void counterWithMutableInteger (Map counterMap) {for (String ország: COUNTRY_NAMES) {counterMap.compute (ország, (k, v) -> v == null? új MutableInteger (0): v). növekmény (); }}
Ban,-ben mapWithMutableInteger módszerrel, miközben a COUNTRY_NAMES tömb, mi:
- felhívni a get a counterMap az országnév kulcsként történő átadásával
- ellenőrizze, hogy a kulcs már van-e vagy sem. Ha egy bejegyzés hiányzik, létrehozunk egy példányát MutableInteger amely a számláló értékét 1-re állítja. Növeljük a MutableInteger ha az ország jelen van a térképen
Ez a módszer a számláló létrehozására jobb, mint az előző - ahogy ugyanazt felhasználjuk MutableInteger és ezáltal kevesebb tárgyat hoz létre.
Így működik az Apache Collections HashMultiSet működik, ahol beágyazza a HashMap értékkel mint MutableInteger belsőleg.
3. Teljesítményelemzés
Itt található a diagram, amely összehasonlítja a fent felsorolt módszerek teljesítményét.
A fenti diagram a JMH használatával jön létre, és itt van a fenti statisztikát létrehozó kód:
Map counterMap = új HashMap (); Map counterMutableIntMap = new HashMap (); Térkép számlálóWithIntArrayMap = új HashMap (); Térkép számlálóWithLongWrapperMap = új HashMap (); @Benchmark public void wrapperAsCounter () {counterWithWrapperObject (counterMap); } @Benchmark public void lambdaExpressionWithWrapper () {counterWithLambdaAndWrapper (counterWithLongWrapperMap); } @Benchmark public void parallelStreamWithWrapper () {counterWithParallelStreamAndWrapper (counterWithLongWrapperStreamMap); } @Benchmark public void mutableIntegerAsCounter () {counterWithMutableInteger (counterMutableIntMap); } @Benchmark public void mapWithPrimitiveArray () {counterWithPrimitiveArray (counterWithIntArrayMap); }
4. Következtetés
Ebben a gyors cikkben bemutattuk a Java használatával a szószámlálók létrehozásának különféle módjait.
Ezeknek a példáknak a megvalósítása megtalálható a GitHub projektben - ez egy Maven-alapú projekt, ezért könnyen importálhatónak és futtathatónak kell lennie.