Archive for March, 2008

Using collect on Groovy collections

Saturday, 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

Thursday, 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

Wednesday, 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).