The original iteration using Enumerable#each calculates the 5 factorial:
def factorial factorial_number result = 1 (1..factorial_number).each{|number| result *= number } result end factorial 5 => 120can be refactored to the more descriptive:
def factorial factorial_number (1..factorial_number).inject(1){|result, number| result *= number } end factorial 5 => 120There are 2 points to be noticed.
- you can initialise the iterators looping variable (result) value by just assigning it to inject
- inject returns the calculated iterators looping variable itself
(while Enumerable#each returns the array again)
Another example using the above mentioned factorial function puts all factorials into a Hash:
factorials = {} [1, 2, 3, 4, 5].each do |number| factorials[number.to_s] = factorial(number) end factorials => {"5"=>120, "4"=>24, "3"=>6, "2"=>2, "1"=>1}which can be easily refactored to:
[1, 2, 3, 4, 5].inject({}) do |factorials, number| factorials[number.to_s] = factorial(number) factorials end => {"5"=>120, "4"=>24, "3"=>6, "2"=>2, "1"=>1}This refactoring may not as obvious as the first example in the first view. But consider you save an initialising line and you make sure to everyone what your intention is:
you process an Enumerable (Array) and return an Enumerable (Hash) without having cumbersome code snippets. At least the Hash object doesn't need to be declared outside the iteration, which is far cleaner.
Be explicit in your code intentions!
There is an alias for Enumerable#inject, called Enumerable#reduce. It's really a matter of taste which one you prefer.
Supported by Ruby 2.1.0
Keine Kommentare:
Kommentar veröffentlichen