Groovy Notes

In this post I describe the data transformation methods present in Groovy that usually have a completely different name in groovy. This may help you get your footing if you are coming from a background in Scala, Python, Ruby, Haskell, Rust, etc.

zip -> transpose

In other languages, you’ll often find a zip method that takes two lists and returns a list of 2-arity tuples. In Groovy, this concept is covered by transpose. Transpose, as the name implies, performs a transposition of the provided list of lists. Additionally, transpose can operate on an arbitrary number of lists. If the lists are of uneven lengths, the result will be of the length of the shortest list.

List letters = [ 'a', 'b', 'c', 'd' ]
List numbers = [  1,   2,   3,   4  ]

List transposed = [letters, numbers].transpose()

assert transposed == [
    [ 'a', 1 ],
    [ 'b', 2 ],
    [ 'c', 3 ],
    [ 'd', 4 ]
]

// Now for an uneven sample
letters = [ 'a' ]

transposed = [letters, numbers].transpose()
List otherTransposed = [numbers, letters].transpose()

assert transposed == [
    [ 'a', 1 ]
]
assert otherTransposed == [
    [ 1, 'a' ]
]

map -> collect

The map concept, by which a function F(A) -> B is applied to the elements of a collection, is called collect in Groovy. As seen in the sample below, the original collection is not modified.

List oddNumbers = [1, 3, 5]
List evenNumbers = oddNumbers.collect { it + 1 }

assert oddNumbers.every { it % 2 == 1 }
assert evenNumbers.every { it % 2 == 0 }

flatten -> flatten

Flatten, thankfully, has the same name one would expect. This recursively collapses collections into a single collection. Unfortunately, Groovy doesn’t have a Maybe / Option type, so flattening is only really useful for collapsing collections.

List one = [1]
List two = [[2]]
List three = [[[3]]]
List four =  [[[[4]]]]

assert [one, two, three, four].flatten() == [1, 2, 3, 4]

flatMap -> collectMany

A common idiom, given the map and flatten utilities, is to map over collections and flatten the result into a simple result. Many languages offer a flatMap to cover this. In Groovy, strangely, this is called collectMany. I suppose the name describes what hey consider the common case - applying collect to many collections. In other languages, I would often map a collection, sometimes generating None (or an empty list) for invalid or error conditions, and then flatten the result so only the valid results are present. This can be accomplished in Groovy as well (though it’s not quite as straight forward).

List ones = [1, 2, 3]
List tens = [10, 20, 30]
List hundreds = [100, 200, 300]

List result = [ones, tens, hundreds].collectMany { l ->
    l.collect { it + 1 }
}

assert result == [2, 3, 4, 11, 21, 31, 101, 201, 301]

class Sample {
    int value

    boolean isValid() {
        // Pretend this is a more complex implementation
        return this.value % 2 == 0
    }
}

List samples = [1,2,3,4,5].collect { new Sample(value: it) }

// Note - this contrived example could be accomplished with a filter,
// but I wanted to show how you might "squish out" invalid results
// using collectMany
List validSamples = samples.collectMany { sample ->
    sample.isValid() ? [ sample ] : []
}

assert validSamples.every { it.isValid() }

WARNING! collectMany does not recursively flatten!

// Consider the following:
assert [1, 2, 3].collect { [[[[it]]]] }.flatten() == [1, 2, 3]
assert [1, 2, 3].collectMany { [[[[it]]]] } == [[[[1]]], [[[2]]], [[[3]]]]

:-(

filter -> findAll

In other languages, you use a filter operation to remove (or preserve, language depending) all members of a collection meeting some criteria. In Groovy, the findAll method accomplishes this.

List numbers = [ 1, 2, 3, 4, 5, 6 ]

List odd = numbers.findAll { it % 2 == 1 }
List even = numbers.findAll { it % 2 == 0 }

assert odd.every { it % 2 == 1 }
assert even.every { it % 2 == 0 }

any - any

As shown in a few examples above, the any method can be used to assert that a predicate holds true for at least one member of a collection.

assert ['foo', 'bar', 'baz'].any { it == 'baz' }
assert ['foo', 'bar', 'baz'].any { it == 'tomato' } == false

all -> every

Also seen above, the every method can be used to assert that a predicate holds true for all members of a collection.

assert ['1', '2', '3'].every { it.isNumber() }
assert ['1', '2', '3', 'four'].every { it.isNumber() } == false

foldl -> inject

The foldl concept is confusingly named inject in groovy. This method takes a seed value and a two param closure with the accumulator and the next value as params.

assert [1, 2, 3].inject(1) { acc, x -> acc * x } == 6
assert [1, 2, 3].inject(0) { acc, x -> acc + x } == 6
assert [1, 2, 3].inject([:]) { acc, x -> acc + [(x): x*2] } == [1:2, 2:4, 3:6]

That’s all for now. I’ll probably update this list as I find more things worth noting.