This is the expected behaviour. According to the ri documentation for inject,
the value passed as argument is the initial value used for the block-local
variable which stores the result and, if you don't give any, the first element
of the array will be used as initial value, so the block (or, in your case,
the method you use instead of the block) is not called on it.
By the way, this is a very strange way to use inject, since you aren't
actually interested in accumulating the values returned by the block (of
course, assuming this is your actual code). In your case, a simple each should
work:
%w/ap mathn roots facets/.each{|f| require f}
I hope this helps
Stefano
···
On Monday 27 December 2010 17:15:27 jzakiya wrote:
When I do this:
%w/ap mathn roots facets/.inject :require
whatever is the first item in the list doesn't get loaded by 'require'
When I do this:
%w/ap mathn roots facets/.inject 0, :require or .inject(0, :require)
then the first item is also loaded. (the '0' can be essentially
anything)
Is this a bug, or is this the expected operation?
This behavior is consistent across 1.8.7, 1.9.1/2 and jruby using RVM.
because 'require' operates on one item at a time
whereas these are equivalent:
(1..100).inject :+
(1..100).inject 0, :+
because '+' operates on two items at a time?
No. The two forms differ as follows:
(1..100).inject 0, :+
···
---------------------
starts with accumulator of 0
then calls :+, 1
then calls :+, 2
...
then calls :+, 100
(1..100).inject :+
------------------
starts with accumulator of 1 (i.e. the first element)
then calls :+, 2
then calls :+, 3
...
then calls :+, 100
Again, my focus in why 'inject' behaves differently under these two
examples.
Inject with an initial value applies the given block to each element.
Originally, this was the only form of inject available.
The newer alternative, of inject without an initial value, takes the
first value of the enumeration as the initial value. Hence the block is
only called for the second to last values.
Those are equivalent by luck only. With inject if you fail to provide the
initial "value" (as you do in the first line) then the first element of the
collection is used (in the first line it would be 1).
So, for example if you used :* or :- instead of :+ for your two rows you
would see a different result for the two rows - using :* would return a very
large number for the first row and zero for the second row (the second row
would just keep multiplying numbers by 0 which always equals 0). For :- you
would have something like -5049 and the second row would be -5050 (or
something close to that).
In the example you provided your second row uses 0 as the initial value
which means after processing the first element of the collection you are in
the same position as not having provided the value, as the first row does,
because 1 = 0 + 1.
John
···
On Mon, Dec 27, 2010 at 9:25 AM, jzakiya <jzakiya@gmail.com> wrote:
Combines all elements of enum by applying a binary operation,
specified by a block or a symbol that names a method or operator.
If you specify a block, then for each element in enum<i>
the block is passed an
accumulator value
(<i>memo) and the element. If you specify a symbol instead,
then each element in the collection will be passed to the named method of
memo. In either case, the result becomes the new value for
memo. At the end of the iteration, the final value of memo is
the return value fo the method.
If you do not explicitly specify an initial value for
memo, then uses the first element of collection is used as the initial
value of memo.
Examples:
# Sum some numbers
(5..10).reduce(:+) #=> 45
# Same using a block and inject
(5..10).inject {|sum, n| sum + n } #=> 45
# Multiply some numbers
(5..10).reduce(1, :*) #=> 151200
# Same using a block
(5..10).inject(1) {|product, n| product * n } #=> 151200
# find the longest word
longest = %w{ cat sheep bear }.inject do |memo,word|
memo.length > word.length ? memo : word
end
longest #=> "sheep"
The point of inject is to push some value through all of the elements. You
just want to iterate over them, which is the #each method.
Since inject wants to push something through the elements, you have to give
it the initial value of the object to push through. In your second example,
you give zero for the initial value. In the one before that, you do not give
it zero. This causes it to use the first element. Then it invokes the plus
on that element, and passes the next element. The result is then pushed
through for the next iteration.
So when you try injecting with numbers and plus, you get
(1..3).inject(0,:+) expands to (((0+1)+2)+3)
(1..3).inject(:+) expands to ((1+2)+3)
Which have the same value.
But when you try that with require, you get
%w/lib1 lib2 lib3/.inject(0, :require) expands to (((0.require
'lib1').require 'lib2').require 'lib3')
%w/lib1 lib2 lib3/.inject(:require) expands to (('lib1'.require
'lib2').require 'lib3')
Which doesn't even make sense. require belongs to Kernel, and we want to
invoke it as if it were a function, not a method on 0 or the string "lib1"
or the boolean value that would be returned if require were properly
executed. So you can see that inject is about repeatedly passing the next
element to the result of the previous, using the specified method. Thus some
value gets "pushed through" (at least that is how I think about it in my
brain), but you are just trying to pass each element to the require
"function". For that, you would use each, and pass a block instead of a
symbol. %w(lib1 lib2 lib3).each { |lib| require lib }
···
On Mon, Dec 27, 2010 at 11:25 AM, jzakiya <jzakiya@gmail.com> wrote:
On Dec 27, 4:23 am, Ryan Davis <ryand-r...@zenspider.com> wrote:
> On Dec 27, 2010, at 00:55 , Skye Shaw!@#$ wrote:
>
> >> Is this a bug, or is this the expected operation?
>
> > Expected, though it's an odd way to require libs. Use %/ap
> > mathn .../.each { |lib| require lib }
>
> Even better, use simple code for simple problems:
>
> require "ap"
> require "mathn"
> # ...etc...
>
> It REALLY isn't cleaning anything up to use enumeration there.