Groovy - Collections

Groovy has native language support for collections, lists, maps and arrays.

Lists

You can create lists as follows. Notice that [] is the empty list expression.

list = [5, 6, 7, 8]
assert list.get(2) == 7
assert list instanceof java.util.List

emptyList = []
assert emptyList.size() == 0
emptyList.add(5)
assert emptyList.size() == 1

Each list expression creates an implementation of java.util.List.

Ranges

Ranges allow you to create a list of sequential values. These can be used as Lists since Range extends java.util.List
Ranges defined with the .. notation are inclusive (that is the list contains the from and to value).
Ranges defined with the ... notation are exclusive, they include the first value but not the last value.

// an inclusive range
range = 5..8
assert range.size() == 4
assert range.get(2) == 7
assert range instanceof java.util.List
assert range.contains(5)
assert range.contains(8)

// lets use an exclusive range
range = 5...8
assert range.size() == 3
assert range.get(2) == 7
assert range instanceof java.util.List
assert range.contains(5)
assert ! range.contains(8)

Note that ranges are implemented efficiently, creating a lightweight Java object containing a from and to value.

Ranges can be used for any Java object which implements java.lang.Comparable for comparison and also have methods next() and previous() to return the next / previous item in the range.


e.g. you can use Strings in a range

// an inclusive range
range = 'a'..'d'
assert range.size() == 4
assert range.get(2) == 'c'
assert range instanceof java.util.List
assert range.contains('a')
assert range.contains('d')
assert ! range.contains('e')

Ranges can be used to iterate using the for statement.

for (i in 1..10) {
  println "Hello ${i}"
}

Maps

Maps can be created using the following syntax. Notice that [:] is the empty map expression.

map = ["name":"Gromit", "likes":"cheese", "id":1234]
assert map.get("name") == "Gromit"
assert map.get("id") == 1234
assert map instanceof java.util.Map

emptyMap = [:]
assert emptyMap.size() == 0
emptyMap.put(5, "foo")
assert emptyMap.size() == 1
assert emptyMap.get(5) == "foo"

Maps also act like beans so you can use the property notation to get/set items inside the Map provided that the keys are Strings which are valid Groovy identifiers.

map = ["name":"Gromit", "likes":"cheese", "id":1234]
assert map.name == "Gromit"
assert map.id == 1234

emptyMap = [:]
assert emptyMap.size() == 0
emptyMap.foo = 5
assert emptyMap.size() == 1
assert emptyMap.foo == 5

Slicing with the subscript operator

You can index into Strings, Lists, arrays, Maps, regexs and such like using the subscript expression.


text = "nice cheese gromit!"
x = text[2]

assert x == "c"
assert x.class == String

sub = text[5..10]
assert sub == 'cheese'

map = ["name":"Gromit", "likes":"cheese", "id":1234]
assert map['name'] == "Gromit"

list = [10, 11, 12]
answer = list[2]
assert answer == 12

Notice that you can use ranges to extract part of a List/array/String/regex. This is often referred to as slicing in scripting languages like Python. You can also use a list of indexes too.

list = 100..200
sub = list[1, 3, 20..25, 33]
assert sub == [101, 103, 120, 121, 122, 123, 124, 125, 133]

You can update items using the subscript operator too

list = ["a", "b", "c"]
list[2] = "d"
list[0] = list[1]
list[3] = 5
assert list == ["b", "b", "d", 5]

You can use negative indices to count from the end of the List, array, String etc.

text = "nice cheese gromit!"
x = text[-1]
assert x == "!"

name = text[-7..-2]
assert name == "gromit"

Also if you use a backwards range (the starting index is greater than the end index) then the answer is reversed.

text = "nice cheese gromit!"
name = text[3..1]
assert name == "eci"