Today, we?re taking a look at Ruby?s inject method (#inject). As anyone who is far enough along on their journey to learn more about coding, you know languages are filled with confusing, awesome methods and functions. Recently, I came across one of these confusing, and as I?ve learned, awesome methods, inject. I was trying to sum an array of integers and mistakenly thought that ruby had a native #sum method, but no such luck. So, I got to googling and found #inject.
The #inject method acts the same as the #reduce method, and they are considered aliases. These enumerator methods can take a range or array of numbers, and can optionally receive a block. When called, the inject method will pass each element and accumulate each sequentially.
[3, 6, 10, 13].inject(:+) => (((3 + 6) + 10) + 13) => 32
OR
[3, 6, 10].inject {|sum, number| sum + number} =>|3, 6| 3 + 6 => 9 =>|9, 10| 9 + 10 =>19
To break this down even further, inject takes the first element in your collection and uses that as the base ?sum?. It then takes the next element (or the second element in the array) and then adds them together. The method then assigns that result to the ?sum? and adds in the next element in the collection until all elements have been passed through the block. In this case, ?sum? is what we call an accumulator ? as it is accumulating the values. The return value will be the sum of all the elements in the collection.
This method is curious because you can also pass it a default value for the accumulator. See below:
[3, 6, 10, 13].inject(0, :+) => 32[3, 6, 10].inject(0) {|sum, number| sum + number} => 19
Here, you are giving the method a starting value for the accumulator, since I passed it zero, the method will add the first element of the collection to zero before moving on to the addition of the second and third elements in the collection.
Now that we know how to add values from collections? Let?s explore the other applications of #inject.
Building Hashes:
#Inject can be very powerful outside of adding values together. Lets say you have data or a return value that is an array of arrays which contain keys and values (i.e. [[:key, value], [:key2, value2]]). You?re most likely going to want those to be key: value pairs in a hash. Inject can very quickly and elegantly help you get that done.
[[:student, “Terrance Koar”], [:course, “Web Dev”]].inject({}) do |result, element| result[element.first] = element.last resultend#=> {:student=>”Terrance Koar”, :course=>”Web Dev”}
In this example we start out with an array of arrays containing key and value pairs. When we call inject and pass in an argument of an empty hash, which will act as the accumulator (or in this case ?result?). Then the method iterates through each element and injects it into the hash using the block provided. The block is assigning the key element, which comest first, as a key in the new hash and setting the value equal to the second element in the nested array. Another thing to note here is that the return value of inject is the next yielded result (typically the sum of integers). Since we want our hash, we need to explicitly return the ?result? hash.
Additionally, inject can be used to convert data types with the help of some other cool methods ? even while it?s building a new hash!
[[:student, “Terrance Koar”], [:course, “Web Dev”]].inject({}) do |result, element| result[element.first.to_s] = element.last.upcase resultend# => {“student”=>”TERRANCE KOAR”, “course”=>”WEB DEV”}OR[[:student, “Terrance Koar”], [:course, “Web Dev”]].inject({}) do |result, element| result[element.first.to_s] = element.last.split resultend# => {“student”=>[“Terrance”, “Koar”], “course”=>[“Web”, “Dev”]}
Inject doesn?t stop there though. It can also filter and build a new array!
[10, 20, 30, 5, 7, 9, 3].inject() do |result, element| result << element.to_s if element > 9 resultend# => [“10”, “20”, “30”]
Here we are passing inject an initial value of an empty array. The first element between the || will always be the ?result? or accumulator in the block. So, once result is set equal to an empty array, we can shovel in any element that passes our filter, in this case if the element is greater than 9. Again, since inject?s return value is the next yielded result, we need to explicitly return the result.
Inject is mainly useful and encouraged when you need to iterate through a collection one element at a time to build a new object, like the above new arrays or hashes, or just return the sum of a collection of integers. Thanks for reading, and I hope you are as excited about the #inject method as I am!