Groovy Shots - Collections - Spread operator

Sometimes it looks more natural handling collections and maps using operators rather than to use the correspondent method call. The spread operator in Groovy is one of those.

Groovy Shell

To write the examples I’m using the Groovy shell. To start the Groovy shell go to your terminal and start the Groovy shell:

start groovy shell
[user]$ groovysh -q
groovy:000>

I’ve minimized the verbosity of the Groovy shell in the examples by replacing the groovy:000> prompt by just >. Also remember that in the Groovy shell you may not want to use the def keyword to define a variable (here you can see why)

Lists

Of course the first case is to create an empty list:

empty list
> empty = []
> assert empty.size() == 0

Notice you can initialize the new list with any number of elements:

adding an element
> myList = [1]

Now I would like to add one more element to the end of the previous list. Here the spread operator is used to add all elements from myList inside newList before the new element 2.

adding new element at the end
> myList  = [1]
> newList = [*myList, 2]
> assert newList == [1, 2]

Or adding a new element at the beginning of the previous list.

adding new element at the beginning
> myList  = [1]
> newList = [0, *myList]
> assert newList == [0, 1]

The previous examples were pretty trivial, and could be also be tackled by other operators available to lists:

adding elements simpler
> myList = [1]
> myList = [0] + myList // adding at the beginning
> myList = myList << 2  // adding at the end
> assert myList == [0, 1, 2]

But when adding in the middle of some lists, the spread operator really shines:

adding in the middle
> myList  = [4, 5]
> newList = [1, 2, 3, *myList, 6, 7, 8]
> assert newList == [1, 2, 3, 4, 5, 6, 7, 8]

Then you can also add two different lists:

adding two lists
> topTen = [*[1, 3, 5, 7, 9], *[2, 4, 6, 8, 10]]
> assert topTen == [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]

Which is the same as adding one list to the other with simply + operators:

adding two lists
> topTen = [1, 3, 5, 7, 9] + [2, 4, 6, 8, 10]
> assert topTen == [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]

You can also use array syntax to specify which elements of the list you would like to use. In the following example I’m combining two lists using a range as the initial source list.

combining two lists
> range = (0..10)
> mirror = [*range[1..6], *range[5..1]]
> assert mirror == [1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]

What about removing elements from a given list. Deleting one element is as simple as using the - operator:

remove one element
> myList = [1, 2, 3, 4, 5] - 5
> assert myList = [1, 2, 3, 4]

I can delete more than one element by subtracting one list to another:

remove more than one element
> myList = [1, 2, 3, 4, 5] - [3, 5]
> assert myList = [1, 2, 4]

Maps

In maps spread operator can also be useful, specially when overriding values from a given map. Lets say we have a configuration map, and some of the entries are common to all scenarios whereas some elements can be changed.

override values
> common = [y: 200, x: 100, type: "circle", color: "green"]
>
> pointA = [
>   *: common,
>   x: 200,
> ]
>
> assert pointA == [y: 200, x: 200, type: "circle", color: "green"]

Obviously changing the order will lead to always override my values:

override values
> common = [y: 200, x: 100, type: "circle", color: "green"]
>
> pointA = [
>   x: 200,
>   *: common,
> ]
>
> assert pointA == [y: 200, x: 100, type: "circle", color: "green"]

Next, like we did in the lists examples we can do normal operations such as adding up whole maps:

adding two maps
> mapA = [a: 1, b: 2, c: 3]
> mapB = [d: 4]
> mapAB = [*: mapA, *: mapB]
> assert mapAB == [a: 1, b: 2, c: 3, d: 4]

To add only some elements of a map to another map there’s no operator for the subMap method. For completeness I’m adding here an example using the subMap method:

subMap
> mapA = [a: 1, b: 2, c: 3]
> mapB = [d: 4]
> mapAB = [*: mapA.subMap("a", "c"), *: mapB]
> assert mapAB == [a: 1, c: 3, d: 4]

Lastly you can remove entries from a map with the minus operator as we did previously in list:

removing elements from map
> mapA = [a: 1, b: 2, c: 3, d: 4, e: 5]
> mapB = mapA - [b: 2, c: 3, d: 4]
> assert mapB == [a: 1, e: 5]

Again is also important to highlight the subMap method here as the example could be simplified:

subMap
> mapA = [a: 1, b: 2, c: 3, d: 4, e: 5]
> mapB = mapA - mapA.subMap("b".."d")
> assert mapB == [a: 1, e: 5]

Notice how subMap can take a range of map keys as parameter, building a map with a series of map entries.

Versions

  • Groovy 2.5.13