12

I often find myself building lookup tables in Ruby, generally to cache some expensive computation or to build something I'm passing to a view. I figure there must be a short, readable idiom for this, but we couldn't think of one. For example, suppose I want to start with

[65, 66, 67, ...]

and end up with

{65 => "A", 66 => "B", 67 => "C", ...}

The not-quite-pretty-enough idioms we could think of include:

array = (65..90).to_a

array.inject({}) {|hash, key| hash[key]=key.chr; hash}
{}.tap {|hash| array.each {|key| hash[key] = key.chr}}
Hash[array.zip(array.map{|key| key.chr})]

But all of these are a little painful: hard to read, easy to mess up, not clear in intent. Surely Ruby (or some Rails helper) has some nice magic for this?

2 Answers 2

25

What about

 Hash[(65..90).map { |i| [i, i.chr] }]

I think this is quite obvious and self-explaining. Also, I don't there exists a much simpler way to solve this rather specific task, Ruby unfortunately doesn't have something comparable to dict comprehension in Python. If you want, you can use the Facets gem, which includes something close:

require 'facets'
(65..90).mash { |i| [i, i.chr] }
Sign up to request clarification or add additional context in comments.

7 Comments

Wow. I never would have guessed that a bunch of array pairs would have been interpreted in that way. I would have expected it to turn into {[65, "A"] => [66, "B"], [67, "C"] => [68, "D"], ...}. That scares me a little, but I'll still use it. Thanks!
@William: You can use Hash.[] in two forms: Hash[key, value, key, value, ...] or Hash[[[key, value], [key, value], ... ]] with the inner array representing any enumerable yielding key/value pairs. Remember that in Ruby, there's more than one to do it :P Also, I added another suggestion using facets.
Sure enough. Right there in the docs. Thanks! I'll definitely check out Facets as well; looks great.
If ever my associate proposal makes it through (see [ruby-core:33683]), you could write array.associate(&:chr) in this case.
@Marc-AndréLafortune: That'd be really nice. Actually I tried .mash(&:chr) because I though this was how it worked. Good luck with that proposal :)
|
1

I think the most idiomatic way from Ruby 2.1 onwards is to use .to_h since it can be called on a block like so:

(65..90).map { |i| [i, i.chr] }.to_h

Comments

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.