מחשבון תדרי מילים יעיל בג'אווה

1. סקירה כללית

במדריך זה נציג דרכים שונות ליישום מונה מילים ב- Java.

2. יישומים נגד

נתחיל בפשטות בחישוב ספירת המילים במערך זה:

מחרוזת סטטית [] COUNTRY_NAMES = {"סין", "אוסטרליה", "הודו", "ארה"ב", "ברית המועצות", "בריטניה", "סין", "צרפת", "פולין", "אוסטריה", "הודו" , "ארה"ב", "מצרים", "סין"}; 

אם אנו רוצים לעבד קבצי ענק, עלינו ללכת על אפשרויות אחרות המתוארות כאן.

2.1. מַפָּה עם שלמים

אחד הפתרונות הפשוטים ביותר יהיה ליצור מַפָּה, אחסן מילים כמפתחות ומספר המופעים כערכים:

מפה counterMap = HashMap חדש (); עבור (מדינה מחרוזת: COUNTRY_NAMES) {counterMap.compute (מדינה, (k, v) -> v == null? 1: v + 1); } assertEquals (3, counterMap.get ("סין"). intValue ()); assertEquals (2, counterMap.get ("הודו"). intValue ());

פשוט השתמשנו מַפָּהזה שימושי לְחַשֵׁב שיטה המגדילה את הדלפק או מאותחל אותו עם 1 אם המפתח אינו קיים.

למרות זאת, שיטה זו ליצירת מונה אינה יעילה כמו מספר שלם הוא בלתי משתנה, ולכן בכל פעם שאנחנו מגדילים את הדלפק, אנחנו יוצרים חדש מספר שלם לְהִתְנַגֵד.

2.2. ממשק API של זרם

עכשיו, בואו ננצל את Java 8 Stream API, במקביל זרמים, וה קיבוץ לפי() אספן:

@ מבחן פומבי בטל כאשר MapWithLambdaAndWrapperCounter_runsSuccessfully () {Map counterMap = HashMap new (); Stream.of (COUNTRY_NAMES) .collect (Collectors.groupingBy (k -> k, () -> counterMap, Collectors.counting ()); assertEquals (3, counterMap.get ("China"). IntValue ()); assertEquals (2, counterMap.get ("הודו"). IntValue ());} 

באופן דומה, נוכל להשתמש ב- parallelStream:

@ מבחן פומבי בטל כאשר MapWithLambdaAndWrapperCounter_runsSuccessfully () {Map counterMap = HashMap new (); Stream.of (COUNTRY_NAMES) .parallel () .collect (Collectors.groupingBy (k -> k, () -> counterMap, Collectors.counting ()); assertEquals (3, counterMap.get ("סין"). IntValue ( assertEquals (2, counterMap.get ("הודו"). intValue ());} 

2.3. מַפָּה עם מספר שלם מַעֲרָך

לאחר מכן, בואו נשתמש ב- מַפָּה שעוטף דלפק בתוך מספר שלם מערך המשמש כערך:

@ מבחן ציבורי בטל whenMapWithPrimitiveArrayCounter_runsSuccessfully () {Map counterMap = HashMap new (); counterWithPrimitiveArray (counterMap); assertEquals (3, counterMap.get ("סין") [0]); assertEquals (2, counterMap.get ("הודו") [0]); } counter void counterWithPrimitiveArray (Map counterMap) {עבור (מדינה מחרוזת: COUNTRY_NAMES) {counterMap.compute (country, (k, v) -> v == null? new int [] {0}: v) [0] ++ ; }} 

שימו לב איך יצרנו פשוט מפת גיבוב עם מערכי int כערכים.

בתוך ה counterWithPrimitiveArray תוך כדי איטרציה על כל ערך במערך, אנו:

  • להפעיל א לקבל על countermap על ידי העברת שם המדינה כמפתח
  • בדוק אם כבר היה מפתח או לא. אם הערך כבר קיים, אנו יוצרים מופע חדש של מערך מספרים שלם פרימיטיבי עם "1" יחיד. אם הערך נעדר, אנו מגדילים את ערך הנגד הקיים במערך

שיטה זו טובה יותר מיישום העטיפה - מכיוון שהוא יוצר פחות אובייקטים.

2.4. מַפָּה עם משתנה שלם

לאחר מכן, בואו ליצור אובייקט עטיפה שמטביע מונה שלם פרימיטיבי כמו להלן:

מחלקה סטטית פרטית MutableInteger {int count = 1; תוספת חלל ציבורית () {this.count ++; } // גטר וקובע} 

בואו נראה כיצד נוכל להשתמש בשיעור הנ"ל כמונה:

@ מבחן ציבורי בטל whenMapWithMutableIntegerCounter_runsSuccessfully () {Map counterMap = HashMap new (); mapWithMutableInteger (counterMap); assertEquals (3, counterMap.get ("סין"). getCount ()); assertEquals (2, counterMap.get ("הודו"). getCount ()); } counter void counterWithMutableInteger (Map counterMap) {עבור (מדינה מחרוזת: COUNTRY_NAMES) {counterMap.compute (country, (k, v) -> v == null? new MutableInteger (0): v). increment (); }}

בתוך ה mapWithMutableInteger שיטה, תוך איטרציה בכל מדינה במדינה COUNTRY_NAMES מערך, אנחנו:

  • להפעיל קבל על countermap על ידי העברת שם המדינה כמפתח
  • בדוק אם המפתח כבר קיים או לא. אם ערך נעדר, אנו יוצרים מופע של משתנה שלם שקובע את ערך הנגד כ- 1. אנו מגדילים את ערך הנגד הקיים ב- משתנה שלם אם המדינה נמצאת במפה

שיטה זו ליצירת מונה טובה יותר מזו הקודמת - כשאנחנו משתמשים באותו שימוש מחדש משתנה שלם ובכך ליצור פחות אובייקטים.

כך אוספי אפאצ'י HashMultiSet עובד במקום שהוא משובץ א מפת גיבוב עם ערך כ משתנה שלם כְּלַפֵּי פְּנִים.

3. ניתוח ביצועים

להלן התרשים המשווה את הביצועים של כל אחת מהשיטות המפורטות לעיל.

התרשים שלמעלה נוצר באמצעות JMH והנה הקוד שיצר את הסטטיסטיקה לעיל:

Map counterMap = HashMap חדש (); מונה counterMutableIntMap = HashMap חדש (); מפה counterWithIntArrayMap = חדש HashMap (); Counter counterWithLongWrapperMap = HashMap חדש (); @Benchmark wrapperAsCounter חלל ציבורי () {counterWithWrapperObject (counterMap); } @Benchmark ציבורי בטל lambdaExpressionWithWrapper () {counterWithLambdaAndWrapper (counterWithLongWrapperMap); } @Benchmark חלל ציבורי parallelStreamWithWrapper () {counterWithParallelStreamAndWrapper (counterWithLongWrapperStreamMap); } @Benchmark ציבורי בטל mutableIntegerAsCounter () {counterWithMutableInteger (counterMutableIntMap); } @Benchmark public void mapWithPrimitiveArray () {counterWithPrimitiveArray (counterWithIntArrayMap); } 

4. מסקנה

במאמר מהיר זה, המחשנו דרכים שונות ליצור מוני מילים באמצעות Java.

את היישום של דוגמאות אלו ניתן למצוא בפרויקט GitHub - זהו פרויקט מבוסס Maven, כך שיהיה קל לייבא ולהפעיל אותו כמות שהוא.


$config[zx-auto] not found$config[zx-overlay] not found