Maps
Prerequisites: Lists
A map stores key → value pairs. [key: value] creates a
java.util.LinkedHashMap, which remembers insertion order.
def user = [name: 'Ada', age: 36, city: 'London']
println user.name // property-style access
println user['age'] // subscript access
println user.get('city')
println user.email // missing key: null
println user.getOrDefault('email', 'n/a')
println user.size()
println user.keySet()
println user.values()
Ada
36
London
null
n/a
3
[name, age, city]
[Ada, 36, London]
Keys written like name: are strings. user.name and
user['name'] both look up the key 'name'.
Changing a map
def stock = [apples: 3]
stock.pears = 5
stock['plums'] = 2
stock.apples += 10
stock.remove('pears')
println stock
println stock.containsKey('plums')
def key = 'kiwis'
def more = [(key): 4, 'with space': 1] // (expr) uses a variable as key
println stock + more
[apples:13, plums:2]
true
[apples:13, plums:2, kiwis:4, with space:1]
To use a variable's value as a key in a literal, wrap it in
parentheses: [(key): 4]. Without them, [key: 4] means the string
'key'.
Looping over a map
def prices = [coffee: 3.5, tea: 2.8, cake: 4.2]
prices.each { item, price ->
println "$item costs $price"
}
for (entry in prices) {
println "${entry.key.toUpperCase()}=${entry.value}"
}
coffee costs 3.5
tea costs 2.8
cake costs 4.2
COFFEE=3.5
TEA=2.8
CAKE=4.2
Map gotchas
def m = [class: 'A', size: 3]
println m.class // looks up the key "class"!
println m.getClass().simpleName
println m.size // key "size"
println m.size() // the method
println([:].isEmpty())
A
LinkedHashMap
3
2
true
Property syntax on a map always means "look up this key", so m.class
returns null when there's no class key. Use getClass() when you
want the class. [:] is an empty map.
Practice
Count how many times each word appears in 'a b a c b a' using a map,
and print the result.
Show solution
def counts = [:]
'a b a c b a'.tokenize().each { word ->
counts[word] = (counts[word] ?: 0) + 1
}
println counts
[a:3, b:2, c:1]
Level 2 shows the one-liner: words.countBy { it }.