מפות בגרובי

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

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

במאמר זה נבחן את דרך העבודה הגרובית עם מפות.

2. יצירת גרובי מַפָּהס

אנו יכולים להשתמש בתחביר המילולי של המפה [k: v] ליצירת מפות. בעיקרון, זה מאפשר לנו ליצור מפה ולהגדיר ערכים בשורה אחת.

ניתן ליצור מפה ריקה באמצעות:

def emptyMap = [:]

באופן דומה, ניתן לייצר מפה עם ערכים באמצעות:

def map = [שם: "ג'רי", גיל: 42, עיר: "ניו יורק"]

שים לב ש המפתחות אינם מוקפים במרכאות.

וכברירת מחדל גרובי יוצר מופע של java.util.LinkedHashMap. אנו יכולים לעקוף התנהגות ברירת מחדל זו באמצעות ה- כפי ש מַפעִיל.

3. הוספת פריטים

נתחיל בהגדרת מפה:

def map = [name: "Jerry"]

אנו יכולים להוסיף מפתח למפה:

מפה ["גיל"] = 42

אך דרך נוספת כמו Javascript משתמשת בסימון מאפיינים (אופרטור הנקודה):

map.city = "ניו יורק"

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

אנו יכולים גם להשתמש במשתנים במקום מילוליות כמפתחות תוך הוספת פריטים חדשים למפה:

def hobbyLiteral = "hobby" def hobbyMap = [(hobbyLiteral): "Singing"] map.putAll (hobbyMap) assertTrue (hobbyMap.hobby == "Singing") assertTrue (hobbyMap [hobbyLiteral] == "שירה")

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

4. אחזור פריטים

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

למפה המוגדרת כ:

def map = [שם: "ג'רי", גיל: 42, עיר: "ניו יורק", תחביב: "שירה"]

אנו יכולים לקבל את הערך המתאים למפתח שֵׁם:

assertTrue (map ["name"] == "Jerry")

אוֹ

assertTrue (map.name == "Jerry")

5. הסרת פריטים

אנו יכולים להסיר כל ערך ממפה על בסיס מפתח באמצעות ה- לְהַסִיר() שיטה. אבל, לפעמים נצטרך להסיר מספר ערכים ממפה. ניתן לעשות זאת באמצעות מִינוּס() שיטה.

ה מִינוּס() השיטה מקבלת א מַפָּה. ומחזיר חדש מַפָּה לאחר הסרת כל הערכים של המפה הנתונה מהמפה הבסיסית:

מפת def = [1:20, a: 30, 2:42, 4:34, ba: 67, 6:39, 7:49] def minusMap = map.minus ([2:42, 4:34]); assertTrue (minusMap == [1:20, a: 30, ba: 67, 6:39, 7:49])

לאחר מכן, אנו יכולים גם להסיר ערכים על סמך תנאי. ניתן להשיג זאת באמצעות להסיר את כל() שיטה:

minusMap.removeAll {it -> it.key instance of String} assertTrue (minusMap == [1:20, 6:39, 7:49])

להפך, כדי לשמור על כל הערכים העומדים בתנאי, אנו יכולים להשתמש ב- retainAll () שיטה:

minusMap.retainAll {it -> it.value% 2 == 0} assertTrue (minusMap == [1:20])

6. איטרציה דרך ערכים

אנו יכולים לחזור באמצעות ערכים באמצעות כל אחד()ו eachWithIndex () שיטות.

ה כל אחד() השיטה מספקת פרמטרים מרומזים כמו כְּנִיסָה, מַפְתֵחַ, ו ערך שמתאימים לזרם כְּנִיסָה.

ה eachWithIndex () השיטה מספקת גם אינדקס בנוסף ל- כְּנִיסָה. שתי השיטות מקבלות א סגירת מעגל כוויכוח.

בדוגמה הבאה אנו חוזרים על כל אחת מהן כְּנִיסָה. ה סגירת מעגל עבר ל כל אחד() השיטה מקבלת את צמד ערכי המפתח מהערך הפרמטר המשתמע ומדפיס אותו:

map.each {entry -> println "$ entry.key: $ entry.value"}

לאחר מכן, אנו משתמשים ב- eachWithIndex () שיטה להדפסת האינדקס הנוכחי יחד עם ערכים אחרים:

map.eachWithIndex {entry, i -> println "$ i $ entry.key: $ entry.value"}

אפשר גם לשאול את מַפְתֵחַ, ערך, ואינדקס מסופקים בנפרד:

map.eachWithIndex {key, value, i -> println "$ i $ key: $ value"}

7. סינון

אנחנו יכולים להשתמש ב- find (), findAll () ו grep () שיטות לסינון וחיפוש ערכי מפות על סמך מקשים וערכים.

נתחיל בהגדרת מפה לביצוע שיטות אלה:

def map = [שם: "ג'רי", גיל: 42, עיר: "ניו יורק", תחביב: "שירה"]

ראשית, אנו מסתכלים על למצוא() שיטה המקבלת א סגירת מעגל ומחזיר את הראשון כְּנִיסָה שתואם את סגירת מעגל מַצָב:

assertTrue (map.find {it.value == "New York"}. key == "city")

בדומה לכך, מצא הכל מקבל גם א סגירת מעגל אבל מחזירה א מַפָּה עם כל צמדי ערך המפתח העומדים בתנאי ה- סגירת מעגל:

assertTrue (map.findAll {it.value == "ניו יורק"} == [עיר: "ניו יורק"])

אם נעדיף להשתמש ב- רשימה, עם זאת, אנו יכולים להשתמש grep במקום מצא הכל:

map.grep {it.value == "New York"}. כל {it -> assertTrue (it.key == "city" && it.value == "New York")}

ראשית השתמשנו ב- grep כדי למצוא ערכים בעלי הערך כניו יורק. ואז, כדי להדגים את סוג ההחזרה הוא רשימה, אנו חוזרים על התוצאה של grep (). ולכל אחד כְּנִיסָה ברשימה הזמינה בפרמטר המשתמע, אנו בודקים אם התוצאה הצפויה שלה.

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

בואו לבדוק אם כל הערכים במפה הם מסוג חוּט:

assertTrue (map.every {it -> it.value instance of String} == false)

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

assertTrue (map.any {it -> it.value instance of String} == true)

8. שינוי ואיסוף

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

בואו נסתכל על כמה דוגמאות.

ניתן מפת תעודות עובדים ועובדים:

def map = [1: [name: "Jerry", age: 42, city: "New York"], 2: [name: "Long", age: 25, city: "New York"], 3: [name : "דסטין", גיל: 29, עיר: "ניו יורק"], 4: [שם: "דסטין", גיל: 34, עיר: "ניו יורק"]]

אנו יכולים לאסוף את שמות כל העובדים לרשימה באמצעות לאסוף():

def names = map.collect {entry -> entry.value.name} assertTrue (names == ["Jerry", "Long", "Dustin", "Dustin"])

לאחר מכן, אם אנו מעוניינים בקבוצת שמות ייחודית, אנו יכולים לציין את האוסף על ידי העברת a אוסף לְהִתְנַגֵד:

def uniqueNames = map.collect ([] כ HashSet) {entry -> entry.value.name} assertTrue (uniqueNames == ["Jerry", "Long", "Dustin"] כסט)

אם אנו רוצים לשנות את שמות העובדים במפה מקט לאותיות גדולות, נוכל להשתמש בה collectEntries. שיטה זו מחזירה מפה של ערכים שהשתנו:

def idNames = map.collectEntries {key, value -> [key, value.name]} assertTrue (idNames == [1: "Jerry", 2: "Long", 3: "Dustin", 4: "Dustin"] )

לבסוף, אפשר גם להשתמש לאסוף שיטות בשילוב עם למצוא ו מצא הכל שיטות כדי לשנות את התוצאות המסוננות:

def under30Names = map.findAll {it.value.age value.name} assertTrue (below30Names == ["Long", "Dustin"])

כאן ראשית אנו מוצאים את כל העובדים בגילאי 20-30 ואוספים אותם במפה.

9. קיבוץ

לפעמים אנו עשויים לרצות לקבץ כמה פריטי מפה למפות משנה על פי תנאי.

ה groupBy () שיטה מחזירה מפה של מפות. וכל מפה מכילה זוגות של ערכי מפתח המעריכים את אותה התוצאה עבור התנאי הנתון:

def map = [1:20, 2: 40, 3: 11, 4: 93] def subMap = map.groupBy {it.value% 2} assertTrue (subMap == [0: [1:20, 2:40] , 1: [3:11, 4:93]])

דרך נוספת ליצור תת-מפות היא באמצעות תת-מפה (). זה שונה ב groupBy () במובן זה שהוא מאפשר קיבוץ רק על סמך המקשים:

def keySubMap = map.subMap ([1,2]) assertTrue (keySubMap == [1:20, 2:40])

במקרה זה, הערכים עבור המקשים 1 ו- 2 מוחזרים במפה החדשה, וכל הערכים האחרים מושלכים.

10. מיון

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

ניתן מפה:

מפת def = [ab: 20, a: 40, cb: 11, ba: 93]

אם יש לבצע מיון לפי המפתח, השתמש ב- no-args סוג() שיטה המבוססת על סדר טבעי:

def באופן טבעיOrderedMap = map.sort () assertTrue ([a: 40, ab: 20, ba: 93, cb: 11] == natureOrderedMap)

או השתמש ב- מיין (Comparator) שיטה לספק היגיון השוואה:

def compSortedMap = map.sort ({k1, k2 -> k1 k2} כ- Comparator) assertTrue ([a: 40, ab: 20, ba: 93, cb: 11] == compSortedMap)

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

def cloSortedMap = map.sort ({it1, it2 -> it1.value it1.value}) assertTrue ([cb: 11, ab: 20, a: 40, ba: 93] == cloSortedMap)

11. מסקנה

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

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

כמו תמיד ניתן למצוא את הדוגמאות המכוסות במאמר ב- GitHub.