כיצד לספור אלמנטים כפולים באררייליסט

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

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

2. לולאה עם Map.put ()

התוצאה הצפויה שלנו תהיה מַפָּה אובייקט, המכיל את כל האלמנטים מרשימת הקלט כמפתחות וספירת כל אלמנט כערך.

הפיתרון הכי פשוט להשיג זאת יהיה לעבור דרך רשימת הקלט ולכל רכיב:

  • אם ה resultMap מכיל את האלמנט, אנו מגדילים מונה ב -1
  • אחרת, אנחנו לָשִׂים ערך מפה חדש (אלמנט, 1) למפה
ספירת מפות ציבורית ByClassicalLoop (רשימת קלט רשימה) {Map resultMap = HashMap חדש (); עבור (אלמנט T: inputList) {if (resultMap.containsKey (element)) {resultMap.put (element, resultMap.get (element) + 1L); } אחר {resultMap.put (אלמנט, 1L); }} להחזיר resultMap; }

ליישום זה יש את התאימות הטובה ביותר, שכן הוא עובד על כל גרסאות הגאווה המודרניות.

אם איננו זקוקים לתאימות שלפני Java 8, נוכל לפשט את השיטה שלנו עוד יותר:

count public map countByForEachLoopWithGetOrDefault (List inputList) {Map resultMap = חדש HashMap (); inputList.forEach (e -> resultMap.put (e, resultMap.getOrDefault (e, 0L) + 1L)); return resultMap; }

לאחר מכן, בואו ניצור רשימת קלט לבדיקת השיטה:

רשימה פרטית INPUT_LIST = Lists.list ("expect1", "expect2", "expect2", "expect3", "expect3", "expect3", "expect4", "expect4", "expect4", "expect4"); 

ועכשיו בואו נאמת זאת:

בטל פרטי validResult (Map resultMap) {assertThat (resultMap) .isNotEmpty (). hasSize (4) .containsExactly (entry ("expect1", 1L), entry ("expect2", 2L), entry ("expect3", 3L) , ערך ("expect4", 4L)); } 

נשתמש שוב ברתמת הבדיקה הזו בשאר הגישות שלנו.

3. לולאה עם Map.compute ()

בג'אווה 8, שימושי לְחַשֵׁב() שיטה הוצגה בפני מַפָּה מִמְשָׁק. אנו יכולים לעשות שימוש גם בשיטה זו:

count public mapByForEachLoopWithMapCompute (List inputList) {Map resultMap = HashMap חדש (); inputList.forEach (e -> resultMap.compute (e, (k, v) -> v == null? 1L: v + 1L)); return resultMap; }

הודעה (k, v) -> v == null? 1L: v + 1L היא פונקציית מיפוי מחדש המיישמת את BiFunction מִמְשָׁק. עבור מפתח נתון, הוא מחזיר את הערך הנוכחי שלו בתוספת אחד (אם המפתח כבר קיים במפה) או מחזיר את ערך ברירת המחדל של אחד.

כדי להפוך את הקוד לקריא יותר, נוכל לחלץ את פונקציית המיפוי מחדש למשתנה שלה או אפילו לקחת אותה כפרמטר הקלט עבור ה- countByForEachLoopWithMapCompute.

4. לולאה עם Map.merge ()

כשמשתמש Map.compute (), אנחנו חייבים להתמודד עם ריק ערכים מפורשים - למשל, אם מיפוי למפתח נתון אינו קיים. זו הסיבה שיישמנו א ריק בדוק את פונקציית המיפוי מחדש שלנו. זה, לעומת זאת, לא נראה יפה.

בואו ננקה את הקוד שלנו בעזרת Map.merge () שיטה:

count public mapByForEachLoopWithMapMerge (List inputList) {Map resultMap = חדש HashMap (); inputList.forEach (e -> resultMap.merge (e, 1L, Long :: sum)); return resultMap; }

עכשיו הקוד נראה נקי ותמציתי.

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

שימו לב שהפעם השתמשנו ארוך :: סכום כמו BiFunction יישום ממשק.

5. זרם API Collectors.toMap ()

מכיוון שכבר דיברנו על Java 8, אנחנו לא יכולים לשכוח את ה- API של Stream. הודות ל- API של Stream, אנו יכולים לפתור את הבעיה בצורה קומפקטית מאוד.

ה למפות() אספן עוזר לנו להמיר את רשימת הקלט ל- מַפָּה:

ספירת מפה ציבוריתByStreamToMap (רשימת inputList) {return inputList.stream (). collect (Collectors.toMap (Function.identity (), v -> 1L, Long :: sum)); }

ה למפות() הוא אספן נוח, שיכול לעזור לנו להפוך את הזרם לשונה מַפָּה יישומים.

6. זרם API Collectors.groupingBy () ו Collectors.counting ()

חוץ מ ה למפות(), הבעיה שלנו יכולה להיפתר על ידי שני אספנים אחרים, groupingBy () ו סְפִירָה():

מפה ציבורית countByStreamGroupBy (רשימת inputList) {להחזיר inputList.stream (). collect (Collectors.groupingBy (k -> k, Collectors.counting ())); }

השימוש הנכון ב- Java 8 Collectors הופך את הקוד שלנו לקומפקטי וקל לקריאה.

7. מסקנה

במאמר מהיר זה, המחשנו דרכים שונות לחישוב ספירת האלמנטים הכפולים ברשימה.

אם ברצונך להבריח את ArrayList עצמו, תוכל לעיין במאמר העיון.

כמו תמיד, קוד המקור השלם זמין ב- GitHub.


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