מיזוג שתי מפות עם Java 8

1. הקדמה

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

ליתר דיוק, נבחן תרחישי מיזוג שונים כולל מפות עם ערכים כפולים.

2. אתחול

בתור התחלה, בואו נגדיר שניים מַפָּה מקרים:

מפת מפה סטטית פרטית 1 = HashMap חדש (); מפת סטטית פרטית map2 = HashMap חדש ();

ה עוֹבֵד הכיתה נראית כך:

שכבה ציבורית עובד {פרטי מזהה ארוך; שם מחרוזת פרטי; // קונסטרוקטור, גטרס, סטרים}

ואז נוכל לדחוף כמה נתונים אל ה- מַפָּה מקרים:

עובד שכיר 1 = עובד חדש (1L, "הנרי"); map1.put (עובד 1. getName (), עובד 1); עובד שכיר 2 = עובד חדש (22L, "אנני"); map1.put (עובד 2. getName (), עובד 2); עובד שכיר 3 = עובד חדש (8L, "ג'ון"); map1.put (עובד 3. getName (), עובד 3); עובד שכיר 4 = עובד חדש (2L, "ג'ורג '"); map2.put (עובד 4. getName (), עובד 4); עובד שכיר 5 = עובד חדש (3L, "הנרי"); map2.put (עובד 5. getName (), עובד 5);

שים לב, שיש לנו מפתחות זהים עבור עובד 1 ו עובד 5 רשומות במפות שלנו בהן נשתמש בהמשך.

3. Map.merge ()

Java 8 מוסיף חדש לְמַזֵג() לתפקד לתוך java.util.Map מִמְשָׁק.

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

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

ראשית, בואו נבנה חדש מפת גיבוב על ידי העתקת כל הערכים מה- מפה 1:

Map map3 = HashMap חדש (map1);

הבא, בואו נציג את לְמַזֵג() פונקציה יחד עם כלל מיזוג:

map3.merge (מפתח, ערך, (v1, v2) -> עובד חדש (v1.getId (), v2.getName ())

לבסוף, נגרום על ה- מפה 2 ולמזג את הערכים לתוך מפה 3:

map2.forEach ((מפתח, ערך) -> map3.merge (מפתח, ערך, (v1, v2) -> עובד חדש (v1.getId (), v2.getName ())));

בואו נפעיל את התוכנית ונדפיס את התוכן של מפה 3:

ג'ון = עובד {id = 8, שם = "ג'ון"} אנני = עובד {id = 22, שם = "אנני"} ג'ורג '= עובד {id = 2, שם = "ג'ורג'"} הנרי = עובד {id = 1, שם = "הנרי"}

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

כמו כן, אנו שמים לב כי ה- עוֹבֵד לאובייקט של הערך האחרון יש את תְעוּדַת זֶהוּת מ ה מפה 1, והערך נבחר מפה 2.

הסיבה לכך היא הכלל שהגדרנו בפונקציית המיזוג שלנו:

(v1, v2) -> עובד חדש (v1.getId (), v2.getName ())

4. Stream.concat ()

ה זרם API ב- Java 8 יכול גם לספק פיתרון קל לבעיה שלנו. ראשון, עלינו לשלב את שלנו מַפָּה מקרים לאחד זרם. זה בדיוק מה Stream.concat () הפעולה עושה:

זרם משולב = Stream.concat (map1.entrySet (). Stream (), map2.entrySet (). Stream ());

כאן אנו מעבירים את ערכי כניסת המפה כפרמטרים. בשלב הבא עלינו לאסוף את התוצאה שלנו לחדש מַפָּה. לשם כך אנו יכולים להשתמש Collectors.toMap ():

תוצאת מפה = combined.collect (Collectors.toMap (Map.Entry :: getKey, Map.Entry :: getValue));

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

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

(value1, value2) -> עובד חדש (value2.getId (), value1.getName ())

הוא ישתמש בביטוי למבדה בכל פעם שמזהים מפתח כפול.

לבסוף, להרכיב את כולם:

תוצאת מפה = Stream.concat (map1.entrySet (). Stream (), map2.entrySet (). Stream ()) .collect (Collectors.toMap (Map.Entry :: getKey, Map.Entry :: getValue, (value1) , value2) -> עובד חדש (value2.getId (), value1.getName ())));

לבסוף, בואו נפעיל את הקוד ונראה את התוצאות:

ג'ורג '= עובד {id = 2, שם = "ג'ורג'"} ג'ון = עובד {id = 8, שם = "ג'ון"} אנני = עובד {id = 22, שם = "אנני"} הנרי = עובד {id = 3, שם = "הנרי"}

כפי שאנו רואים, הערכים הכפולים עם המפתח "הנרי" אוחדו לצמד ערך מפתח חדש שבו זהות החדש עוֹבֵד נבחר מה מפה 2 והערך מ מפה 1.

5. Stream.of ()

כדי להמשיך להשתמש ב- זרם API, אנחנו יכולים להפוך את שלנו מַפָּה מקרים לזרם מאוחד בעזרת זרם של().

כאן אנחנו לא צריכים ליצור אוסף נוסף כדי לעבוד עם הזרמים:

מפה map3 = Stream.of (map1, map2) .flatMap (map -> map.entrySet (). Stream ()) .collect (Collectors.toMap (Map.Entry :: getKey, Map.Entry :: getValue, (v1 , v2) -> עובד חדש (v1.getId (), v2.getName ())));

ראשון, אנו הופכים מפה 1 ו מפה 2 לזרם יחיד. לאחר מכן, אנו ממירים את הזרם למפה. כפי שאנו רואים, הטיעון האחרון של למפות() היא פונקציית מיזוג. זה פותר את בעיית המפתחות הכפולים על ידי בחירת שדה מזהה מ v1 ערך, והשם מ v2.

המודפס מפה 3 מופע לאחר הפעלת התוכנית:

ג'ורג '= עובד {id = 2, שם = "ג'ורג'"} ג'ון = עובד {id = 8, שם = "ג'ון"} אנני = עובד {id = 22, שם = "אנני"} הנרי = עובד {id = 1, שם = "הנרי"}

6. סטרימינג פשוט

בנוסף, אנו יכולים להשתמש ב- זרם() צינור להרכבת ערכי המפות שלנו. קטע הקוד שלהלן מדגים כיצד להוסיף את הערכים מ מפה 2 ו מפה 1 על ידי התעלמות מהערכים הכפולים:

מפה map3 = map2.entrySet () .stream () .collect (Collectors.toMap (Map.Entry :: getKey, Map.Entry :: getValue, (v1, v2) -> עובד חדש (v1.getId (), v2 .getName ()), () -> HashMap חדש (map1)));

כצפוי, התוצאות לאחר המיזוג הן:

{ג'ון = עובד {id = 8, שם = "ג'ון"}, אנני = עובד {id = 22, שם = "אנני"}, ג'ורג '= עובד {id = 2, שם = "ג'ורג'"}, הנרי = עובד { id = 1, name = "Henry"}}

7. StreamEx

בנוסף לפתרונות המסופקים על ידי ה- JDK, אנו יכולים גם להשתמש בפופולרי StreamEx סִפְרִיָה.

פשוט שים, StreamEx מהווה שיפור עבור זרם ממשק API ומספק שיטות שימושיות רבות נוספות. נשתמש ב- EntryStream מופע להפעלת צמדי ערך מפתח:

Map map3 = EntryStream.of (map1) .append (EntryStream.of (map2)) .toMap ((e1, e2) -> e1);

הרעיון הוא למזג את זרמי המפות שלנו לאחד. ואז אנו אוספים את הערכים אל החדש מפה 3 למשל. חשוב להזכיר, את (e1, e2) -> e1 ביטוי שכן הוא מסייע בהגדרת הכלל להתמודדות עם המפתחות הכפולים. בלעדיו הקוד שלנו יזרוק IllegalStateException.

ועכשיו, התוצאות:

{ג'ורג '= עובד {id = 2, שם = "ג'ורג'"}, ג'ון = עובד {id = 8, שם = "ג'ון"}, אנני = עובד {id = 22, שם = "אנני"}, הנרי = עובד { id = 1, name = "Henry"}}

8. סיכום

במאמר קצר זה למדנו דרכים שונות למיזוג מפות בג'אווה 8. באופן ספציפי יותר, השתמשנו Map.merge (), ממשק API, StreamEx סִפְרִיָה.

כמו תמיד, את הקוד ששימש במהלך הדיון ניתן למצוא באתר GitHub.


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