The power of inject
Author |
Message |
wtd
|
Posted: Tue Apr 05, 2005 2:37 am Post subject: The power of inject |
|
|
For operations on arrays Ruby offers us a powerful feature from the functional programming realm. What's classically known as "fold" or "reduce" there is the inject method in Ruby (the name is from Smalltalk).
Let's consider the simple ask of summing an array of integers.
The simple imperative solution we've probably all seen is:
code: | arr = [1, 3, 23, 56, 789]
sum = 0
arr.each { |x| sum += x } |
This isn't too bad. Ruby makes the loop quite expressive.
But we can do better.
Inject involves taking each element of an array and adding it to the result of doing the same operation on the previous element. Of course, since there is no previous result for he first elemen, we supply an initial value. For addition, let's start with an initial value of zero.
code: | arr = [1, 3, 23, 56, 789]
sum = arr.inject(0) { |a, b| a + b } |
Consider also an example for finding the product of an array of numbers.
code: | arr = [1, 3, 23, 56, 789]
product = arr.inject(0) { |a, b| a * b } |
Questions? Comments? |
|
|
|
|
|
Sponsor Sponsor
|
|
|
jamonathin
|
Posted: Tue Apr 05, 2005 7:45 am Post subject: (No subject) |
|
|
What exactly does this do/mean |
|
|
|
|
|
Tony
|
Posted: Tue Apr 05, 2005 9:18 am Post subject: (No subject) |
|
|
it's a block where |a,b| represent two values in an array and a*b is the function applied to the said values. |
|
|
|
|
|
jamonathin
|
Posted: Tue Apr 05, 2005 11:43 am Post subject: (No subject) |
|
|
Does the ' a * b ' have to be in the | a,b |, it can't be like |
|
|
|
|
|
Tony
|
Posted: Tue Apr 05, 2005 12:31 pm Post subject: (No subject) |
|
|
well since nether C nor D relate to the block of variables, you might as well pre-calculate the result of the function, such as
So to make it clear - you're not restricted to array's objects. You can, for example, have a *5 |
|
|
|
|
|
wtd
|
Posted: Tue Apr 05, 2005 12:33 pm Post subject: (No subject) |
|
|
tony wrote: it's a block where |a,b| represent two values in an array and a*b is the function applied to the said values.
Yes, it's a block.
Says "the block accepts two arguments, and we'll call them a and b."
Is saying the block returns "the sum of a and b."
In this case, though, a and b do not represent two values taken from the array. Rather, a represents the value of the previous operation and b the current element in the array.
For an array like:
code: | [1, 3, 23, 56, 789] |
It would look like:
code: | ((((0 + 1) + 3) + 23) + 56) + 789
(((1 + 3) + 23) + 56) + 789
((4 + 23) + 56) + 789
(27 + 56) + 789
83 + 789
872 |
|
|
|
|
|
|
jamonathin
|
Posted: Wed Apr 06, 2005 9:59 am Post subject: (No subject) |
|
|
ohhh ok, I get it guys, thanks lots |
|
|
|
|
|
wtd
|
Posted: Wed Apr 06, 2005 1:01 pm Post subject: (No subject) |
|
|
tony wrote: well since nether C nor D relate to the block of variables, you might as well pre-calculate the result of the function, such as
If you're not using a block's parameter, then don't include it at all.
code: | $ irb
irb(main):001:0> [1,2,3].inject(0) { |a, b| 42 }
=> 42
irb(main):002:0> [1,2,3].inject(0) { 42 }
=> 42
irb(main):003:0> |
|
|
|
|
|
|
Sponsor Sponsor
|
|
|
wtd
|
Posted: Fri Nov 11, 2005 5:56 pm Post subject: (No subject) |
|
|
What can we do with inject?
We can reverse an Array.
code: | >> foo = [3, 5, 1, 8]
=> [3, 5, 1, 8]
>> foo.inject([]) { |a, b| a.unshift b }
=> [8, 1, 5, 3] |
We can find the length of an Array.
code: | >> foo = [3, 5, 1, 8]
=> [3, 5, 1, 8]
>> foo.inject(0) { |a, _| a + 1 }
=> 4 |
We can get the keys from a Hash.
code: | >> bar = {"hello" => "world", "foo" => "bar"}
=> {"foo"=>"bar", "hello"=>"world"}
>> bar.inject([]) { |a, b| a << b.first }
=> ["foo", "hello"] |
We can invert a Hash.
code: | >> bar = {"hello" => "world", "foo" => "bar"}
=> {"foo"=>"bar", "hello"=>"world"}
>> bar.inject({}) { |a, b| a[b.last] = b.first; a }
=> {"world"=>"hello", "bar"=>"foo"} |
These are just a few examples. |
|
|
|
|
|
|
|