Jason Lillywhite wrote:
> range = (1..4)
> sum = range.inject(0) {|result, element| result += element }

That should be:

  range = (1..4)
  sum = range.inject(0) {|result, element| result + element }

To understand this fully, I will write out what inject is doing in
longhand:

  range = (1..4)
  tmp = 0            # the (0) bit
  range.each do |element|
    result = tmp
    tmp    = result + element
    #(A)#    ######(B)#######
  end
  sum = tmp          # final value of inject

#(B)# is the execution of the block body. #(A)# is done implicitly by
'inject': it stores the value calculated by the block, and then passes
this into the next iteration, or else uses it as the final return value.

> #However, iterating over a hash is confusing me. Here is a simple 
> example:
> 
> hash = [[:diameter, 45], [:id, 2]].inject({}) do |result, element|
>   result[element.first] = element.last
>   result
> end
> 
> #can someone help me understand better what exactly is happening on each 
> iteration?

Written out longhand as above:

  tmp = {}
  [[:diameter, 45], [:id, 2]].each do |element|
    result = tmp
    result[element.first] = element.last
    tmp    = result
    #(A)#    #(B)##
  end
  hash = tmp

To start with the accumulator is set to an empty hash.

After one iteration, you have done hash[:diameter] = 45, so you've added
a new element to the hash. You then give the entire hash object as the
value result from the block, so that it is passed in as 'result' to the
next iteration.

On the next iteration, you do hash[:id] = 2, so you've added a new value
to it. But the same hash object is the result.

In this case, for every iteration the *same* hash object is passed in,
and returned so that it can be used by the following iteration. What
you're doing is modifying that object as a side-effect of the block
executing.

Now, it is possible to get the same result without modifying the hash,
but instead creating a new hash object in each iteration, like this:

  hash = [[:diameter, 45], [:id, 2]].inject({}) do |result, element|
    result.merge({element.first => element.last})
  end

This is what a 'functional' programmer would do, where functions cannot
modify data, only create new data. In each iteration you're merging the
hash built so far with a new one-element hash, to create a new partial
result which is one element larger.

This is less efficient, as you're repeatedly creating larger and larger
hash objects only to be garbage-collected later. But if you were doing
this in (say) Erlang, that's what you'd need to do.

Hope this is a bit clearer now...

Brian.
-- 
Posted via http://www.ruby-forum.com/.