Ross Bamford
3/1/2006 4:37:00 PM
On Thu, 2006-03-02 at 00:14 +0900, Adam Groves wrote:
> Dear Ross,
>
> it works a treat but I'm having a bit of trouble figuring out what's
> going on.
>
> (n < 1) ? '_' : (1...n).inject("A") { |curr, i| curr.succ }
>
> I get this:
> if n<1
> '_'
> else
>
> But I'm stuck here.
>
> (1...n).inject("A") { |curr, i| curr.succ}
>
> I still can't quite get my head around blocks beyond .each do |x|
Inject is real easy, and very handy. It's just like 'each', except it
also allows the result of the previous iteration to be injected via the
first argument. For the first iteration, you provide the initial result.
For example:
a = [1,2,3,4,5]
a.inject(0) { |sum, i| sum + i }
# => 15
What happens is:
Block is called with sum = 0, i = 1
Block returns 1
Block is called with sum = 1, i = 2
Block returns 3
Block is called with sum = 3, i = 3
Block returns 6
Block is called with sum = 6, i = 4
Block returns 10
Block is called with sum = 10, i = 5
Block returns 15
No more elements, so inject returns 15.
In Ruby, inject allows you to omit the initial value, in which case the
first _two_ elements from the enumerable are passed to the first
iteration, with things proceeding as above from there, so I could have
written:
a.inject { |sum, i| sum + i }
And would have:
Block is called with sum = 1, i = 2
Block returns 3
Block is called with sum = 3, i = 3
Block returns 6
.
.
etc.
You can use inject for much more than just summing stuff up. Comes in
very handy for these cryptic one-lines (even if you have to 'misuse' it
a bit occasionally).
--
Ross Bamford - rosco@roscopeco.REMOVE.co.uk