0

When I have an array of hashes or AR objects, I like to do this to get access to certain fields:

products.map(&:upc_code)

Sometimes I have an array of hashes that are instead keyed by a string, and then I can't use the & sign. So instead I have to do:

people.map{ |p| p['Last Name'] }

I know the ampersand can be used to pass a block, but my question is why does it work the way it does in the first statement above. What is it actually doing?

1
  • products.map(&:upc_code) is equivalent to products.map{ |e| e.upc_code }. A hash doesn't respond to the methods named after keys, thus it doesn't work that way with a hash. Commented Apr 2, 2014 at 15:19

2 Answers 2

2

Actually if no block/proc found in functions like map they call to_proc function for argument. In you example actually goes following conversion:

products.map(&:upc_code) => products.map {|a| :upc_code.to_proc.call(a) } 

And actual to_proc method for Symbol looks like (In ruby code):

class Symbol
  def to_proc
    proc { |o| o.send(self) }
  end
end

It return a proc which call a method for ruby object passed as argument. You can override to_proc method for Symbol like below and and to_proc for String to support Hash.

class Symbol
  def to_proc
    proc { |o| 
     if o.is_a?(Hash)
      o.has_key?(self) ? o[self] : self.to_s.to_proc.call(o)
     else
       object.send(self)
     end
    }
  end
end

class String
  def to_proc
    proc { |o|  o.has_key?(self) ? o[self] : nil }
  end
end

a = [{"x" => 2}, {"x" => 3}]
puts a.map(&:x)
puts a.map(&"x")

Results will be:

=> [2, 3]
=> [2, 3]
Sign up to request clarification or add additional context in comments.

Comments

1

Your hash doesnt respond to Last Name, simply. Ie, hash.key doesnt work, its hash[key].

If you use an openstruct, suddenly, it works!

require 'ostruct'
hash = { 'Last Name' => 1 }
[ OpenStruct.new(hash) ].map &:'Last Name'
=> [1]

1 Comment

I see now. I was thinking that map(&:key) magically worked for arrays containing hashes that were keyed with symbols, but that isn't the case at all. It's the AR objects whose attributes can be accessed either by symbol or by method. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.