Groovy Goodness: GroupBy with Multiple Closures

We can group elements in a List or Map with the groupBy() method for a long time in Groovy. We pass a closure with the grouping condition to get a Map with the items grouped. And since Groovy 1.8.1 we can use more than closure to do the grouping. We can use it for both List and Map objects.

import static java.util.Calendar.*

class User {
String name
String city
Date birthDate
public String toString() { name }
}

def users = [
new User(name:'mrhaki', city: 'Tilburg', birthDate: Date.parse('yyyy-MM-dd', '1973-9-7')),
new User(name:'bob', city: 'New York', birthDate: Date.parse('yyyy-MM-dd', '1963-3-30')),
new User(name:'britt', city: 'Amsterdam', birthDate: Date.parse('yyyy-MM-dd', '1980-5-12')),
new User(name:'kim', city: 'Amsterdam', birthDate: Date.parse('yyyy-MM-dd', '1983-3-30')),
new User(name:'liam', city: 'Tilburg', birthDate: Date.parse('yyyy-MM-dd', '2009-3-6'))
]

def result = users.groupBy({it.city}, {it.birthDate.format('MMM')})

assert result.toMapString() ==
'[Tilburg:[Sep:[mrhaki], Mar:[liam]], New York:[Mar:[bob]], Amsterdam:[May:[britt], Mar:[kim]]]'

assert result.Amsterdam.size() == 2
assert result.Tilburg.Mar.name == ['liam']

result = users.groupBy({it.name[0]}, {it.city})
assert result.toMapString() ==
'[m:[Tilburg:[mrhaki]], b:[New York:[bob], Amsterdam:[britt]], k:[Amsterdam:[kim]], l:[Tilburg:[liam]]]'
assert result.k.Amsterdam.name == ['kim']

// groupBy with multiple closues also works on Map
def usersByCityMap = users.groupBy({it.city})
def resultMap = usersByCityMap.groupBy({it.value.size()}, { k,v -> k.contains('i') })
assert resultMap.toMapString() ==
'[2:[true:[Tilburg:[mrhaki, liam]], false:[Amsterdam:[britt, kim]]], 1:[false:[New York:[bob]]]]'
assert resultMap[1].size() == 1
assert resultMap[2].size() == 2
assert resultMap[2][true].Tilburg.name.join(',') == 'mrhaki,liam'