Home > Groovy > [].inject(“Groovy”){}

[].inject(“Groovy”){}

The collection helper methods like each, findAll, and collect are among the clearest productivity advantages of Groovy over Java. For reference, here’s a list of the common collection helper methods on the Groovy Quick Start page (after opening the link you’ll have to scroll down to them).

The inject method is among the most interesting of them all but is not utilized often by Groovy developers. It’s useful but somewhat difficult to understand, relative to the complexity of the other collection helper methods, so many developers get the job done without inject and never bother to learn about it. I encourage everyone to learn inject so that they can understand another approach for attacking their problems and choose the most appropriate approach. The inject method is also a great first step in learning a little about functional programming.

Functional Style – A stork story for inject
The Scala and Clojure languages on the JVM have aroused interest in functional style programming. Even with an imperative language like Java we can alter our programming style to more of a functional one, so learning the functional tenets can be very valuable to your arsenal.

Let’s take some Groovy code that calculates the sum of numbers 1 through 10.
def total = 0
(1..10).each{total += it}
return total

Here we apply a closure to each value in the 1..10 range. But as we repeatly apply this closure we also need to keep track of a total variable, which changes with each iteration.

In pure functional programming variables are… not allowed. This poses an interesting twist to our problem. How can we accomplish the same functionality as the above code without any variables?

The answer to most “How can I solve this without variables?” questions: Recursion.

Let’s examine how we totaled up values 1 to 10:
(((((((((((0)+1)+2)+3)+4)+5)+6)+7)+8)+9)+10)
Each set of paranthesis describes the value of total at some given point in time starting with 0 and expanding out to its final result of 55. Consequently, total gets set to 11 different values over its lifetime and only the last of those 11 was actually what we wanted.

The other danger here is that another developer might “refactor” your code by moving all variable declarations to the top of methods. I’ve inherited Java code like this quite often, where the beginning of some ginormous method sets a bunch of values like total = 0, even though taking the initializing value out of context actually makes the code more confusing.

With inject we can make the value of total clearer by keeping the calculation within the scope of its declaration. We “inject” the initial value of 0 and at each iteration the previousResult value represents what used to be represented by a waffling total variable.
def total = (1..10).inject(0){previousResult, iterationValue ->
  previousResult + iterationValue
}

The concept of inject in Groovy is identical to that of a left fold in functional programming. Ironically, the Groovy’s implementation of inject does not use recursion for, what I’m assuming, are performance reasons.

sum()
We’ve been using a very simple example. Those familiar with Groovy might ask why not just use the sum() method available to lists:
(1..10).sum()

Well, I’m glad you brought it up because there’s more to sum() than you may have realized.

You see, sum() allows you to “inject” an initial value.
(1..10).sum() // 55
(1..10).sum(0) // 55
(1..10).sum(3) // 58

This doesn’t seem incredibly valuable at the surface, but let’s look at why it can be.

Try calling sum() on an empty list:
[].sum() // null

Yes, the result is null. Most folks would assume that the result should be 0. So why isn’t the result 0? You have to realize that the sum() method merely requires that the objects in the list have a plus() method, which means that Groovy’s sum() method can’t assume that the empty list you passed in held Integer values.

For example, you could join strings in a list using sum():
["strings ","in ","a ", "list "].sum() // "strings in a list"

If you had an empty list intended for Strings, a sum() of 0 doesn’t make sense – an empty String would be more appropriate, so use sum(""). If you don’t “initialize” a value into sum() you could end up with null if your list is empty and that could break some assumptions in your code, leading to a NPE. It’s often a good idea to “initialize” the sum() method with a value, much like you would do with inject().

inject() to build collections
Java programmers switching to Groovy often use each{} for everything involving iterations. They write the equivalent of an imperative Java for loop:
def oneToTen = (1..10)
def doubles = []
oneToTen.each{myValue->
  doubles.add(myValue*2);
}
return doubles

They’re often thrilled to find out that using a different collection helper method makes their code more readable and concise:
def doubles = (1..10).collect{ it*2 }

Always scan your Groovy code for a collection helper method code smell:
If your each{} or other collection helper method (findAll, collect, etc.) has a variable declaration in the line before it, you’re likely to benefit by using a different method.

I usually play around in the GroovyConsole (just type groovyConsole in your command line if you have Groovy installed) to decide which collection helper method does the job best. It’s a fun challenge to include inject into the mix even though it has only emerged once as the victor in my production code… and honestly I can’t remember what that was and I don’t have access to the code any more. Bummers.

There’s an inject example at the bottom of a post we made on chaining and currying closures back in November ’08. Chris made a clever improvement in the comments section of that post as well. Thanks for that, Chris! We greatly welcome any improvements or questions here and we hope to see even more in the future from our readers.

Advertisements
  1. January 27, 2009 at 10:34 am

    Great post, Marc! You really hit the nail on the head.

  2. balrog
    May 4, 2009 at 7:20 pm

    Since Groovy does not provide product() methods to accompany its sum() methods, I have found inject() to be indispensable. For another readily-accessible example of inject(), check out this inject-based iterative factorial:

    iFactorial = {
    (it > 1) ? (2..it).inject(1, { i, j -> i*j }) : 1
    }
    (0..6).each { println “${it}: ${iFactorial(it)}” }

  3. May 8, 2009 at 7:07 am

    @balrog That’s really cool – thanks for posting!

  4. Tim Yates
    June 30, 2009 at 11:11 am

    @balrog

    With a quick tweak, you can handle bigger numbers ;-)

    iFactorial = {
    (it > 1) ? ( 2..it ).inject( 1 as BigInteger ) { i, j -> i * j } : 1
    }
    (160..161).each { println “${it}: ${iFactorial(it)}” }

  5. Levin
    August 11, 2009 at 1:04 pm

    guillaume the forge had a fun use of inject, I don’t quite follow it but trying to figure it out lead me here. Thanks for the article hopefully it’ll enlighten me up.

    // from http://groovy.markmail.org/message/bbkf6oepp4rtdxna?q=map

    arabs = [‘1′,’2′,’3′,’4’]
    italians = [‘I’,’II’,’III’,’IV’]
    [arabs,italians].transpose().inject([:]){uh, what -> uh[what[0]] = what[1]; uh}

    //Result: [1:I, 2:II, 3:III, 4:IV]

  1. December 31, 2009 at 3:36 pm
  2. March 16, 2010 at 2:19 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: