Igor Šarčević wrote this on February 18, 2016

# Inject is a fundamental building block

Inject is one of the fundamental, and most versatile constructs available in functional languages. It can be used to implement `map`, `select`, `max`, `all?` and a bunch of other iteration related methods. Unfortunately, many programmers are not aware of its awesome powers. This article is here to improve this fact.

Let’s dig in.

## Simple array iteration

First, let’s start with an example problem — finding the sum of numbers in an array:

```def sum(numbers)
result = 0

numbers.each do |number|
sum += number
end

result
end

sum([1, 3, 5, 7, 9]) # => 25
```

Now, let’s try to solve the same problem with a simple limitation. Let’s calculate the result without changing the values of the variables. In other words, we will try to avoid explicit state changes like in the following example:

```sum += number
```

This is a very important step to make our code more functional. Changing the values of variables, in other words making side effects, is preventing our code to run on multiple processors effortlessly. Side effects are also a common thing that can introduce hard to find bugs.

In the functional world, instead of a `for-each` iteration, programmers use recursion. Let’s rewrite the above code segment with a recursive implementation:

```def sum(numbers)
if numbers.empty?
0
else
first, *rest = numbers

first + sum(rest)
end
end

sum([1, 3, 5, 7, 9]) # => 25
```

It can be a little hard to grasp the idea if this is the first time you are encountering recursion in your life. The idea behind it is, however, very simple. After several tries and errors it can be mastered easily.

## Accumulators

In order to create a more general purpose algorithm, and to optimize it for tail calls we will allow our `sum` method to accept a starting value. We will call it `accumulator`.

```def sum(accumulator, numbers)
if numbers.empty?
accumulator
else
first, *rest = numbers

sum(accumulator + first, rest)
end
end

sum(20, [1, 3, 5, 7, 9]) # => 45
```

The name ‘accumulator’ can be confusing, but you can think of it as a variable that accumulates the result. Its purpose is equivalent to the `result` variable in our original imperative implementation.

## Introducing inject

Now it is safe to introduce the `inject` method — an abstraction for the above recursive construct. Let’s use it to sum numbers:

```[1, 3, 5, 7, 9].inject(20) { |accumulator, number| accumulator + value } # => 45
```

By renaming the variables we can make the above line more straightforward:

```[1, 3, 5, 7, 9].inject(20) { |result, number| result + value } # => 45
```

Let’s use it to calculate the product of an array:

```[1, 3, 5, 7, 9].inject(2) { |result, number| result * number } # => 805
```

The above patters are very handy when we want to convert an array of values into one value. This is one of the main strengths of the `inject` method. In this example we are reducing the array into a single value. This is why the `inject` method is commonly also named `reduce`.

## Less verbose injecting

If you think about it, the `{ |result, number| result + value }` is repeated for both of the above examples. Luckily, Ruby is a powerful language that enables us to write the above lines even shorter. The `:*` is a shorthand value for a block that multiplies its arguments. Let’s use it:

```[1, 3, 5, 7, 9].inject(1, :*) # => 945
```

This representation can give us a deeper insight into the name of the `inject` method. We can think of `inject` as a mechanism that injects a `*` operator between the elements of the array.

```1 * 3 * 5 * 7 * 9
```

### Implementing `sum` and `product`

Let’s implement the `sum` and `product` methods using `inject`:

```def sum(elements, from = 0)
elements.inject(from, :+)
end
```
```def product(elements, from = 1)
elements.inject(from, :*)
end
```

### Implementing `map`

The above example is nice, but it is not nice enough to be called a fundamental iteration block for functional programmers. Luckily, `inject` can do much more. The `map` method can be tough about as a special kind of `inject`. The following two code block are equivalent:

```[1, 2, 3].map { |el| el * el }
```
```[1, 2, 3].inject([]) { |result, el| result + [el * el] }
```

We can even implement a `map` method by using `inject`:

```def map(elements, &block)
elements.inject([]) { |result, el| result + [block.call(el)] }
end
```

### Implementing `select`

We can even implement a `select` method using `inject`:

```def select(elements, &block)
elements.inject([]) { |result, el| result + (block.call(el) ? [el] : []) }
end
```

We can reuse the previous definition of `map` and `sum` to make it shorter:

```def select(elements, &block)
sum(map(elements) { block.call(el) ? [el] : [] })
end
```

Even the `reject` method is simple:

```def reject(elements, &block)
elements - select(elements, &block)
end
```

### Implementing `min` and `max`

We can implement a `min` method that returns the smallest element in the array. The trick is to store the current minimum as the accumulated value:

```def min(elements, &block)
elements.inject(Float::INFINITY) do |minimum, el|
el < minimum ? el : minimum
end
end
```

Symmetrically, the maximum value can be calculated:

```def max(elements, &block)
elements.inject(-Float::INFINITY) do |maximum, el|
el > minimum ? el : maximum
end
end
```

### Implementing `all?`

This is my last example, and hopefully you will be convinced that almost every method in Ruby’s `Enumerable` module can be implemented as an special case of the `inject` function.

Let’s construct the `all?` method that checks if every element in the array satisfies a given check block:

```def all?(elements, &block)
elements.inject(true) { |result, el| result && block.call(el) }
end
```

Similarly, the `any?` method can be implemented:

```def any?(elements, &block)
elements.inject(false) { |result, el| result || block.call(el) }
end
```

## Should I use `inject` to write code?

No.

Many programmers that learn the `inject` method start to use it all over the place. While I admit that `inject` is a truly powerful construct, it is not something that should be used everywhere, especially not in business level logic.

Instead of using `inject` everywhere, use it to construct new, domain level functions that you can use in you code. For example, instead of writing:

```usernames = ["tim", "jake", "jennifer", "marcus"]

end

# => { "tim" => 3, "jake" => 4, "jennifer" => 8, "marcus" => 6 }
```

I encourage you to write a specific method that creates a hash from the input and output array. Let’s call this method `hashmap`:

```def hash_map(elements, &block)
elements.inject({}) do |map, el|
map.merge(el => block.call(el))
end
end
```

Then use it to calculate the same value simpler:

```usernames = ["tim", "jake", "jennifer", "marcus"]

# => { "tim" => 3, "jake" => 4, "jennifer" => 8, "marcus" => 6 }
```

Or even shorter:

```hash_map(usernames, &:length)
```

If you feel ambitious, you can even add it as a method to `Array`:

```def Array
def hash_map(&block)
self.inject({}) do |map, el|
map.merge(el => block.call(el))
end
end
end
```

## Final words

Inject is super awesome, and powerful enough to express most of the iteration logic in functional languages. However, never forget the Spiderman hypothesis:

With great power comes great responsibility.

Happy injecting!

## The Semaphore Guides to CI/CD

When you’re in a field for a long time, you start to believe that what you’re doing is common knowledge.

## Rails Testing Handbook

A new ebook on building test-driven Rails apps with RSpec and Cucumber.

At Rendered Text, we have a long history with Ruby on Rails. Checking the blog archive reminds me that we published first posts about working with Rails way back in 2009.