Groovy vs. Google Collections: Round #2

April 8th, 2008

For Round #2 of our code challenge, Dan has responded to my initial provocation in spades with a efficient example of Google CollectionsMultiMap 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!

Setting up my collection
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.

The real logic
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?

You can add any java library to your groovy project, just like it was a java project.

So let’s add Google’s Collections package as see if we can use it with groovy to make our code nicer!

Groovy and Google’s collections hand-in-hand
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 cars.’Ford’ = ‘Taurus’, but no dice. This isn’t a groovy map, it is a google map, so I’ve lost all my groovy functionality, which isn’t very groovy. And my script from this point on is going to look suspiciously like Dan’s java program. So what is the point of this experiment? Well, it lets me know that if I run into a situation where I’ll need the functionality of a MultiMap, I can easily import the google jar and whip out an inverse-able MultiMap collection. Only, I won’t be able to use all the sugary groovy syntax with it. It is still better to have the option.

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.


Groovy vs. Google Collections: Round #1

April 4th, 2008

In my last post, Dan Lewis (my friend and former coworker) responded with some counter-code from Google’s collections package. Instead of attempting to snap back with some witty technical retort, I challenged Dan to a code-off. Groovy collections vs. Google collections (in Java). Here is round one, and I’m going first with an example of finding combinations of collections. Hopefully, you can soon find Dan’s response in Google collection code-style on his blog.

Create the lists
def boys = ['Paco', 'Sven', 'Roger', 'Emelio']
def girls = ['Julia', 'Prudence', 'Lucy']

Now we have two simple lists, one of boys and one of girls. So what if these are all dancers, and we’d like to know all the combinations of dancers there could be? With groovy, this is extremely easy.

Find the combinations of dancers
def combos = [boys, girls].combinations()

Could it be any easier? This creates a list of lists, each inner list containing a possible combination:

[[”Paco”, “Julia”], [”Sven”, “Julia”], [”Roger”, “Julia”], [”Emelio”, “Julia”], [”Paco”, “Prudence”], [”Sven”, “Prudence”], [”Roger”, “Prudence”], [”Emelio”, “Prudence”], [”Paco”, “Lucy”], [”Sven”, “Lucy”], [”Roger”, “Lucy”], [”Emelio”, “Lucy”]]

Now it would be nice if i could split the list up in some way, maybe keying by male or female. Groovy’s groupBy collection method is an easy way to do this. In the closure you provide, you simple return the key that you want to group the collection by, and it will return a map with that key pointing to a list of values. In the following example, because I know the first element of each combination is the boy and the second is the girl, I just specify a key by element position.

Grouping the combinations
def groupedByBoys = combos.groupBy { it[0] }
def groupedByGirls = combos.groupBy { it[1] }

Which returns these two groupings:

Grouped by boys
[”Emelio”:[[”Emelio”, “Julia”], [”Emelio”, “Prudence”], [”Emelio”, “Lucy”]], “Roger”:[[”Roger”, “Julia”], [”Roger”, “Prudence”], [”Roger”, “Lucy”]], “Sven”:[[”Sven”, “Julia”], [”Sven”, “Prudence”], [”Sven”, “Lucy”]], “Paco”:[[”Paco”, “Julia”], [”Paco”, “Prudence”], [”Paco”, “Lucy”]]]
Grouped by girls
[”Lucy”:[[”Paco”, “Lucy”], [”Sven”, “Lucy”], [”Roger”, “Lucy”], [”Emelio”, “Lucy”]], “Prudence”:[[”Paco”, “Prudence”], [”Sven”, “Prudence”], [”Roger”, “Prudence”], [”Emelio”, “Prudence”]], “Julia”:[[”Paco”, “Julia”], [”Sven”, “Julia”], [”Roger”, “Julia”], [”Emelio”, “Julia”]]]

Beat that, Google Collections!


Using collect on Groovy collections

March 29th, 2008

When you find something you like, you want to share it with the world. Here are some more tricks when working with collections in Groovy that makes programming fun again! ;)

Let’s get a sample model and some data first, then we’ll get to the fun and easy Grooviness…

Let’s create some rock stars!
class RockStar {
    def name
    def bands
    def numberOfGroupies
}

def mike = new RockStar(name:"Mike Patton",
                bands:["Faith No More","Mr. Bungle"],
                numberOfGroupies:2214)
def bono = new RockStar(name:"Bono",
                bands:["U2"],
                numberOfGroupies:543582)
def slash = new RockStar(name:"Saul Hudson",
                bands:["Guns N Roses", "Velvet Revolver"],
                numberOfGroupies:32544)
def scott = new RockStar(name:"Scott Weiland",
                bands:["Stone Temple Pilots", "Velvet Revolver"],
                numberOfGroupies:41880)

def rockStarList = [mike, bono, slash, scott]

As you can see, I have created a simple POGO class, loaded some beans, then tossed them into a simple list.

Now what? Well, maybe we need to make a list of all the bands our rock stars are a part of, or better yet, a set. We don’t want the same band listed twice now! So what is the easiest way to make this happen? Let me introduce you to a very useful method in your Groovy toolbox, collect.

Collect all the bands from the rock stars
Set allBands = rockStarList.collect { rockStar ->
    rockStar.bands
}

The closure you pass to the collect method is used to transform that list item into whatever you want. In this case, I’m taking a list of RockStars and transforming it into a set of string lists, containing band names. When you run this, you will get a Set that contains the Lists within the objects. This is really useful when you have a list of domain classes that you don’t really need, but you need to get at some information inside each of them.

[[”Faith No More”, “Mr. Bungle”], [”Stone Temple Pilots”, “Velvet Revolver”], [”Guns N Roses”, “Velvet Revolver”], [”U2″]]

But this is still no good! We want a List of Strings that contain band names, not a List of Lists! But wait! Groovy makes this dead-easy to fix:

Flatten the bands
Set allBands = rockStarList.collect { rockStar ->
    rockStar.bands
}.flatten()

Using the flatten list method does exactly what we want. It takes all the collections within the top-level collection and adds them recursively to the top-level collection, effectively flattening them all out into one collection.

[”Velvet Revolver”, “Stone Temple Pilots”, “U2″, “Faith No More”, “Guns N Roses”, “Mr. Bungle”]

Perfect. But you want to know the total number of groupies for every rock star? No problem.

Count up the groupies!
def totalGroupies = rockStarList.collect {
    it.numberOfGroupies
}.sum()
If you don’t want to explicitly define the closure parameter for a closure, groovy will default to “it”. This makes it easy to keep the characters you type down to a minimum.

Before we call the sum() method, our closure returns a List containing Integer objects. If you call sum() on a list of any objects, this effectively calls the “plus()” method on each of the objects. Because the list is loaded with Integer objects, these all add up nicely.

Try runnig 1.plus(2) in groovy. Then run 1 + 2. Same answer. The “+” operator is resolved to the “plus()” method on whatever operand it operates on (which is an Integer object, in this case). This happens anywhere in groovy, and with more than just “+”.

And there you go:

620220

There will be 620,220 groupies at the show.


I *heart* POJOs POGOs

March 27th, 2008

To celebrate my new position as a groovy and grails programmer at G2One Inc, I had to update my bumper sticker!

I heart POGOs

Groovy collection comparison is easy

March 26th, 2008

One thing I found myself doing more than I wanted with java was collection comparison. Many times, you might have a large list of all available items, and a smaller list of selected items. Commonly, you might want to find all the items that exist in the large collection, but have not been ’selected’ in the smaller collection. Invariably in java, this means nested loops.

Not so much with groovy.

List subtraction
def smallList = [1,3,5]
def bigList = [1,1,1,2,3,4,4,4,5,6,7,7,8,9]

def result = bigList - smallList
println result.class
println result

The result is:

class java.util.ArrayList
[2, 4, 4, 4, 6, 7, 7, 8, 9]

Groovy correctly made the assumption that I was making a List in my snippet above. And it removed any element within the first list where equals() was true for an element in the first list. That means it took away three 1’s and one 3. Keep in mind the original collections are untouched.

But what if I want to compare a List and a Set?

Set/List addition
Set mySet = [1,3,5]

List myList = [0,1,2,3,4,0,1,2,3,4,5,6,7,8,9]

def addition = myList + mySet
println addition.class
println addition

addition = mySet + myList
println addition.class
println addition

Now we’re adding a List and a Set together, and the result is different depending on which is the first operand:

class java.util.ArrayList
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 3, 5]
class java.util.HashSet
[2, 4, 9, 8, 6, 1, 3, 7, 5, 0]

If the List is the first operand, groovy assumes you want to treat the following operand as a List as well, and it just tacks the values onto the end. But when the Set is first, groovy first converts the second argument into a Set as well before doing its addition. This removes all but unique elements from it before performing the addition.

Set/List subtraction
Set mySet = [1,3,5]

List myList = [0,1,2,3,4,0,1,2,3,4,5,6,7,8,9]

def subtraction = myList - mySet
println subtraction.class
println subtraction

subtraction = mySet - myList
println subtraction.class
println subtraction

We should again see the automatic type conversion as in the above examples depending on which type is the first operand. In the results below, you can see that all elements within the set were removed from the list (there are no 1’s, 3’s, or 5’s). The second subtraction results in 0 elements, because the List (which is converted to a Set) being subtracted contains 1, 3, and 5, so all are removed from the original Set.

class java.util.ArrayList
[0, 2, 4, 0, 2, 4, 6, 7, 8, 9]
class java.util.HashSet
[]

Good stuff. This is just another example of how groovy does away with a lot of the annoying things you have to do with java.

When groovy comes across an operator like “-” or “+”, it looks for a method on the left operand called either “plus” or “minus”. So in the above examples, mySet - myList is the same as mySet.minus(myList).