Groovy vs. Google Collections: Round #2
Tuesday, April 8th, 2008For Round #2 of our code challenge, Dan has responded to my initial provocation in spades with a efficient example of Google Collections‘ MultiMap utilities. His model involves car makes and models, their associations, and the easiest way to travel between them. At the core of the problem is the fact that a make can have many models, and we want an easy collection that will have utilities to get the data from both ends. Touché, my good man, because groovy doesn’t have a utility that matches the MultiMap functionality.
In order to quickly emulate the same data structure, I was forced to push a bunch of single-element maps into a list! Yuck!
def cars = [] cars << ['Ford':'Taurus'] << ['Ford':'Focus'] << ['Ford':'Mustang'] cars << ['Chevrolet':'Malibu'] << ['Chevrolet':'Impala'] << ['Chevrolet':'Corvette'] cars << ['Dodge':'Charger'] << ['Dodge':'Avenger'] << ['Dodge':'Viper']
But at least I have something I can work with now, albeit not the optimal collection that MultiMap would have provided in this case.
def printModels = { make, pair ->
if (pair.any{it.key == make})
println "$make makes ${(pair.values() as List)[0]}"
make
}
def printMake = { model, pair ->
if (pair.any{it.value == model})
println "$model is made by ${(pair.keySet() as List)[0]}"
model
}
cars.inject('Ford', printModels)
cars.inject('Chevrolet', printModels)
cars.inject('Dodge', printModels)
cars.inject('Impala', printMake)
All the work is done in the closures. If I had the MultiMap’s capabilities, I could have created a map that would store multiple values for each key (see Dan’s initial volley), and I could have just called get() to retrieve a set of those values. But my groovy closures are looking specifically for either the key or value in the list of single-element maps. The closures are meant to be used with the inject method of groovy collections. The first printModels closure expects the make to be injected into it, and then compares it to each map key to find whether the current pair should be printed out. The printMakes closure expects the model to be passed, comparing it to the pair values.
I was disappointed to find out that groovy’s map implementation had no inverse operation. In java, this is not possible, because a key can have only one value, and if you try to inverse, you might possibly have a key with many values, breaking java into tiny pieces. Because the MultiMap allows keys to have multiple values, there is no danger in inversing the positions of keys and values, which is very handy (again, see how Dan used it)
The calls to inject actually execute the closures that print out the strings. The first three print out the models for each make injected into the closure, and the last one injects a model and prints out its make.
So there are some pluses, some minuses to using groovy for this sort of problem. On one hand, my total lines of code are still under 20, which is less than Dan’s example. However, I’m using a Frankensteined collection (a list of single-element maps). Can we get the best of both worlds somehow?
So let’s add Google’s Collections package as see if we can use it with groovy to make our code nicer!
import com.google.common.collect.*
def cars = Multimaps.newHashMultimap()
cars.put('Ford','Taurus')
Ok… let’s stop right there. The groovy programmer in me really wanted to add to the map using
In summary, I think the google java collections package is downright cool. Anything that makes programming simpler and easier is good for our business. Groovy is great, but if I were working in java today, I would love this package. Hell, I might even want to use it with groovy someday. Thanks to Dan Lewis for participating in my challenge and being a good sport.

