Injecting Understanding

Written on 3:42:00 PM by S. Potter

Over the past 4 weeks numerous people (Java heads trying out Ruby for the first time, or even coding neophytes that are jumping on board the Ruby train) have asked me about the .inject method. So I will try to demystify a method that (to me) epitomizes Ruby, yet baffles many that first encounter it. First, let's start with the basic concept. Here is some code you might find around in Ruby examples, etc., to demonstrate the purpose of inject:

(1..10).inject(0) { |cumulative_sum, item| cumulative_sum + item } #=> 55
Let's dissect:
  1. (1..10) is an inclusive Range (if you don't know what a Range is in Ruby...better read up here, as it is out of scope for this article) from 1 to 10 (inclusive).
  2. Then because Range is Enumerable (again if you don't know what Enumerable in Ruby up about it here, again out of scope of this posting) it has inject available, so it bears remembering that it isn't just Arrays inject will work on.
  3. We initially pass in 0 (yes, that's zero) as the argument to inject, which tells inject to start the "balance" at 0 (yes, zero again). Then it iterates through all the elements in the Range from 1 to 10 (inclusively remember because we used two dots not three) passing in the cumulative sum (or balance) and the current item into the block you define. The block we defined above is an expression that evaluates to an integer in this case.
  4. The result of this expression is now set to the cumulative_sum (or "balance") carried forward into the next iteration. So as we should have all learned in school Mathematics when getting to summation series', the cumulative sum of 1 through 10 is 55 (this is the result we get from inject from the above code - and not by accident either - this is exactly what inject is all about).
You might also remember (or perhaps it is just sad Math geeks like myself that remember this stuff) that the sum of any set of consecutive numbers (starting from 1) is defined the by formula: (N*(N + 1))/2, where N is the largest of all consecutive numbers in the set. With this knowledge we can sanity check (for our own understanding) whether it does what you should expect it to do or if it was just coincidence above: def sum(n) n*(n+1)/2 end (1..9).inject(0) { |cumulative_sum, item| cumulative_sum + item } #=> 45 sum(9) #=> 45 (1..100).inject(0) { |cumulative_sum, item| cumulative_sum + item } #=> 5050 sum(100) #=> 100 (1..7890).inject(0) { |cumulative_sum, item| cumulative_sum + item } #=> 31129995 sum(7890) #=> 31129995 See told you it wasn't just coincidence - or what everything above a coincidence? Hmmmm..let's not go there right now!:). I'll bet you could very easily figure out the more general formula for any sum of consecutive positive integers not necessarily starting at 1 (yes, that is one). At least that is what my Mathematics teacher would ask us to do for homework (really not very much homework to be honest - I had a nice teacher)! I'll not make you prove it by induction today though;) Maybe tomorrow... Now you can do more interesting things instead of just summing consecutive positive integers. Don't just move on to geometric progressions either - the world is your finding numerical solutions using an iterative method of your choice using this streamlined apporach!

If you enjoyed this post Subscribe to our feed

No Comment

Post a Comment