Ruby’s inject() lets you do amazing things very expressively. I first
got into inject() when realized how easy it makes getting a class by its
fully qualified name:
klass = fully_qualified_name.split(’::’).inject(Module) { |_module,
_symbol|
_module.const_get(_symbol)
}
instance = klass.new
In this example name “inject” totally corresponds to what it is doing
here. To me at least.
Sincerely,
Gennady.
Jeff P. wrote:
As for Inject, nobody has come up with a wording that makes any sense to
me yet. Does Inject have any aliases/synonyms?
How I remember: Inject takes a binary operation (e.g. +) and injects it
between each element of a list.
[1,2,3].inject { |a,b| a+b } => 1+2+3
– Jim W.
On 5/21/06, Jim W. [email protected] wrote:
Jeff P. wrote:
As for Inject, nobody has come up with a wording that makes any sense to
me yet. Does Inject have any aliases/synonyms?
How I remember: Inject takes a binary operation (e.g. +) and injects it
between each element of a list.
[1,2,3].inject { |a,b| a+b } => 1+2+3
Awesome! That really helps me!
Leslie V. wrote:
On 5/21/06, Jim W. [email protected] wrote:
Jeff P. wrote:
As for Inject, nobody has come up with a wording that makes any sense to
me yet. Does Inject have any aliases/synonyms?
How I remember: Inject takes a binary operation (e.g. +) and injects it
between each element of a list.
[1,2,3].inject { |a,b| a+b } => 1+2+3
Awesome! That really helps me!
Seems like “sum” would have been a better name.
Also
[1,2,3].each {|a| b += a}
is easier to read …for me.
Jim W. wrote:
How I remember: Inject takes a binary operation (e.g. +) and injects it
between each element of a list.
[1,2,3].inject { |a,b| a+b } => 1+2+3
– Jim W.
I think about this in a slightly different way, which helps me
rememeber. Something like, “#inject itorates over thie items in order
but also injects the result from the last block call into the current
one.”
(1…5).inject { |injected_value, this_item| injected_value + this_item
} => 15
2006/5/22, Regg Mr [email protected]:
Seems like “sum” would have been a better name.
Definitively not because you can do far more than calculating sums with
inject.
Also
[1,2,3].each {|a| b += a}
is easier to read …for me.
Yes, but it also needs more LOC.
robert
On 5/22/06, Regg Mr [email protected] wrote:
Awesome! That really helps me!
Seems like “sum” would have been a better name.
Or an alias inject_operator perhaps…
This thread has discussed “sum” already and it’s no good because you
can use any operator. I also like “accumulate” as mentioned, but
inject_operator is sooo clear to me.
On 5/22/06, Leslie V. [email protected] wrote:
[1,2,3].inject { |a,b| a+b } => 1+2+3
Awesome! That really helps me!
Seems like “sum” would have been a better name.
Or an alias inject_operator perhaps…
This thread has discussed “sum” already and it’s no good because you
can use any operator. I also like “accumulate” as mentioned, but
inject_operator is sooo clear to me.
…though the other uses of inject defy “inject_operator”…
data = [[1, 7, 3], [1, 2], [1, 5, 4, 1], [1, 8]]
longest_sample = nil
longest_length = data.inject(0) do |accum, sample|
if accum > sample.length
accum
else
longest_sample = sample
sample.length
end
end
puts “Longest sample: #{longest_sample.inspect}, length
#{longest_length}”
…then again, using inject to find longest seems a bit silly…
longest_sample = data[0]
data.each do |sample|
longest_sample = sample if sample.length > longest_sample.length
end
puts “Longest sample: #{longest_sample.inspect}, length
#{longest_length}”
…then again, using inject to find longest seems a bit silly…
longest_sample = data[0]
data.each do |sample|
longest_sample = sample if sample.length > longest_sample.length
end
puts “Longest sample: #{longest_sample.inspect}, length #{longest_length}”
longest_sample = data.max{|a,b| a.length <=> b.length}
Hi –
On Mon, 22 May 2006, Regg Mr wrote:
Awesome! That really helps me!
Seems like “sum” would have been a better name.
Only in the case where you’re calculating a sum Inject does the
sum-like thing but in a generalized way.
David
This is a question that I have often wondered about and I think this
thread
has gone a fair way to explaining it.
Just to make sure, I want to step through a call to inject (The sum
example)
to see that I have it. Any comments would be great.
[1,2,3].inject(0) { |cur_sum, elem| cur_sum + elem }
Iteration 1
cur_sum = 0, elem = 1
cur_sum = cur_sum + elem #=> cur_sum = 0 + 1 (Replace cur_sum with the
results of the block => 1 )
Iteration 2
cur_sum = 1, elem = 2
cur_sum = cur_sum + elem #=> cur_sum = 1 + 2 (Replace cur_sum with the
results of the block => 3 )
Iteration 3
cur_sum = 3, elem = 3
cur_sum = cur_sum + elem #=> cur_sum = 3 + 3 (Replace cur_sum with the
results of the block => 6 )
Return cur_sum #=> 6
I think that part so far is ok. I get this part. but how would I step
through this?
klass = fully_qualified_name.split(’::’).inject(Module) { |_module,
_symbol|
_module.const_get(_symbol)
}
instance = klass.new
2006/5/22, Daniel N [email protected]:
cur_sum = cur_sum + elem #=> cur_sum = 0 + 1 (Replace cur_sum with the
results of the block => 6 )
Return cur_sum #=> 6
I think that part so far is ok. I get this part. but how would I step
through this?
Exactly the same - only values are different.
klass = fully_qualified_name.split(‘::’).inject(Module) { |_module,
_symbol|
_module.const_get(_symbol)
}
instance = klass.new
class Foo;class Bar;class Baz; end end end
=> nil
“Foo::Bar::Baz”.split(/::/).inject(Object) {|cl,n| print "-> ", cl,
", ", n, “\n”; cl.const_get(n)}.new
→ Object, Foo
→ Foo, Bar
→ Foo::Bar, Baz
=> #Foo::Bar::Baz:0x3a3178
Kind regards
robert
Regg Mr wrote:
Two points:
Seems like “sum” would have been a better name.
Unless the operator isn’t + …
[1,2,3].inject { |left, right| left * right }
# => 1*2*3
"A::B".split("::").inject(Object) { |left, right|
left.const_get(right) }
# => Object.const_get(“A”).const_get(“B”)
(2..n).inject(1) { |left, right| left * right }
# => n! => 2*3* ... * n
Also
[1,2,3].each {|a| b += a}
is easier to read …for me.
Perhaps, but there is a fundamental difference between the inject and
each versions. The “each” verison is procedural. It defines state (the
value of b) and how that state changes in each iteration (b += a).
The “inject” version is functional. There are no extra state variables
in our code that need initialization. And the expression itself is the
value, rather than having a side effect on a local variable.
Not that one way is better than the other, just noting differences.
– Jim W.
sample.length
end
end
puts “Longest sample: #{longest_sample.inspect}, length
#{longest_length}”
…then again, using inject to find longest seems a bit silly…
Well, Enumerable#max is the way to go here, but inject isn’t
that clumsy too:
longest = data.inject{|max, this| this.length > max.length ? this : max}
puts “Longest sample: #{longest.inspect}, length #{longest.length}”
I love it, it’s the swiss army knife of Enumerable.
cheers
Simon
On 5/21/06, Logan C. [email protected] wrote:
Epsilon). Calculus and Physics are “twenty some odd years ago” for
me.
I think you mean Sigma. And I believe when you don’t refer to it as
sigma you say “Summation”.
But I am not a mathematician, so take what I said with a grain of salt.
The big Sigma is often called the n-ary sum operator, and there’s a
corresponding big Pi called the n-ary product (it can be implemented
as inject where the operation in the block is *).
So, in math-speak, I think one could say:
inject applies a block pairwise as an n-ary operation over an
Enumerable, with an optional initial value.
This may or may not help anyone understand it.
-A
“Kroeger, Simon (ext)” [email protected] writes:
Well, Enumerable#max is the way to go here, but inject isn’t
that clumsy too:
longest = data.inject{|max, this| this.length > max.length ? this : max}
longest = data.inject{|max, this| [this.length, max.length].max }
(That’s how they do it in APL too, btw.)
Christian N. schrieb:
longest = data.inject{|max, this| [this.length, max.length].max }
(That’s how they do it in APL too, btw.)
I know why I prefer Ruby
data = %w"hello christian and APL"
p data.inject{|max, this| [this.length, max.length].max }
=> undefined method `length’ for 9:Fixnum (NoMethodError)
Regards,
Pit
On 5/22/06, Farrel L. [email protected] wrote:
…then again, using inject to find longest seems a bit silly…
longest_sample = data[0]
data.each do |sample|
longest_sample = sample if sample.length > longest_sample.length
end
puts “Longest sample: #{longest_sample.inspect}, length #{longest_length}”
longest_sample = data.max{|a,b| a.length <=> b.length}
Yes precisely! That’s what I like about Ruby, everyone’s a smartypants!
(one day I will be too!)
Hi,
On 5/24/06, Pit C. [email protected] wrote:
=> undefined method `length’ for 9:Fixnum (NoMethodError)
This works:
p data.inject(0){|max, this| [this.length, max].max }
And in APL it’s 4 Unicode characters plus the symbol:
(max)(reduce)(shape)(each)data,
where (reduce) is an operator on (max) producing the function which
is equivalent to Ruby’s inject method.
So there …
Stuart
I must say I’m surprised that my tired old thread is still kicking
around.
If I may summarize, the reason I was confused by Inject is that it is
useful but poorly named.
many thanks for all the replies,
jp