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: array, enumerable, inject, ruby




I think you have a typo in the last example – the last line before end should have names.last not words.last
Yes it’s a typo. Thanks Dmitry
You can slightly simply the above idiom:
# From:
n == names.last ? string
Either way, love the ternary use. Ok, bye.
Oops, it ate my comment, should be:
# From:
n == names.last ? string
Doesn’t like my entity chars?
# From:
n == names.last ? string << name : string << “#{name}, ”
# To:
string << ((n==names.last) ? name : string + “,”)
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!).
Your last example would be easier to do with map and join:
string = names.map {|n| n.length > 4 ? n.capitalize : n }.join(“, “)
Your blog is interesting!
Keep up the good work!
This could be interesting
sum = nums.inject(0) { |x,n| x+n }
is equal
sum = nums.inject(:+)