Groovy Functional Programming - Reduce Operation with inject

One of the common tasks in programming is to generate a summary from a collection of data. To make the concept easy for understanding, consider the following list of numbers.

def numbers = [1, 2, 3, 4, 5, 6, 7]

Suppose we want to find the sum of number in the above list. Let's start with the imperative solution.

def computeSum(def numbers) {
    def sum = 0
    for(number in numbers) {
        sum += number

println computeSum(numbers) // 28

Let's now attempt to find another form of summary, say maximum value among the numbers.

def computeMax(def numbers) {
    def max = 0
    for(number in numbers) {
        max = Math.max(max, number)
println computeMax(numbers) // 7

Observe the above two solutions closely for the common patterns. The only difference in the solutions is -  given two numbers in adjacent positions, how do we arrive at an interim result and how do we arrive at the next interim result considering the current interim result and the next number in the list. This idea can be implemented as follows.

def sum = { number1, number2 ->
    number1 + number2

def max = { number1, number2 ->
    Math.max(number1, number2)

def summarise(def numbers, def strategy) {
    def result = 0
    for(number in numbers) {
        result = strategy(result, number)

println summarise(numbers, sum) // 28
println summarise(numbers, max) // 7

Again, I chose to implement sum and max as closures so that I can pass them as arguments to the function summarise

If you are not familiar with Groovy closures, this post has the details.

However, you don't have to write that summarise method. It's available in Groovy with the name inject. You reinventing the wheel is not a good idea. Hence let's refactor the above code to use inject.

println numbers.inject(0, sum) // 28
println numbers.inject(0, max) // 7
print numbers.inject(max) // without initial value

You may want to take a look at the slides from my FunctionalConf talk for more examples.

Show Comments