Ruby Inject

You probably frequently have to iterate through a list and accumulate a result that changes as you iterate. Let’s take the following array:

nums = [1, 3, 5, 7]

If you want to find a sum of all the items in the array, you could write something like this:

sum = 0
nums.each { |n| sum += n }

This works fine, but it doesn’t look much elegant. Luckly, for us that wants to be elegant there is a inject method.
(See: Enumerable::inject)

sum = nums.inject(0) { |x,n| x+n }

This code does the same thing, but also looks cool. Inject acomplish this by using accumulator or accumulated value (x). At each step accumulated value is set to the value returned by the block. Here, we set accumulator initial value to 0, and at each step current value from array (n) is added to accumulated value.

If initial value is omitted, the first item is used as the accumulator initial value and is then omitted from iteration.

sum = nums.inject { |x,n| x+n }

Is same as

sum = nums[0]
nums[1..-1].each { |n| sum += n }

Another example.
We have array with five names:

names = ["michael", "ron", "scottie", "dennis", "toni"]

The following code:

string = names.inject("") { |x,n| x << "#{n} " }

Will output:

=> "michael ron scottie dennis toni "

You can get the same output with:

string = ""
names.each { |n| string << "#{n} "}

Now, let’s say you won’t to separate them with comma, and capitalize those that have more then four characters.
You can do it like this:

string = ""
names.each do |n|
  name = n.length > 4 ? n.capitalize : n
  n == names.last ? string << name : string << "#{name}, " 
end

Or like this:

string = names.inject("") do |x,n|
  name = n.length > 4 ? n.capitalize : n
  n == names.last ? x << name : x << "#{name}, "
end

In both ways we get the same result:

=> "Michael, ron, Scottie, Dennis, toni"

Technorati Tags: , , ,

Advertisements

9 thoughts on “Ruby Inject

  1. Doesn’t like my entity chars?
    # From:
    n == names.last ? string << name : string << “#{name}, ”
    # To:
    string << ((n==names.last) ? name : string + “,”)

    Like

  2. Great article! thanks. And if you like idioms you should check this page outhttp://www.k-international.com/french_idiomsIt gives a list of French idioms with their English translations – really shows how funny language is out of context (and what a nightmare it can be to translate languages!). 🙂

    Like

  3. Your last example would be easier to do with map and join:

    string = names.map {|n| n.length > 4 ? n.capitalize : n }.join(“, “)

    Like

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