0

So this is a trivial, but hopefully fun question. I need to make a Hash with identical keys and values from the keys of an existing Hash. Here's an example input along with my best attempt so far:

input = {'cat' => 'meow', 'dog' => nil}
Hash[*input.keys.map {|k| [k,k]}.flatten]
#=> {'cat' => 'cat', 'dog' => 'dog'}

I don't think this is particularly readable, so I was wondering if there was a better, more expressive syntax for doing this in Ruby, particularly one that might be more readable for future programmers who maintain the code?

This is how I would do the same thing in Python, and I find it to be slightly more readable:

dict([[a,a] for a in input])

But that could just be because I'm used to reading Python!

Looking for suggestions that will work with Ruby 1.8.6, which is the version I am constrained to.

prairiedogg
  • 6,323
  • 8
  • 44
  • 52
  • possible duplicate of [How do I copy a hash in Ruby?](http://stackoverflow.com/questions/4157399/how-do-i-copy-a-hash-in-ruby) – Josh Lee Dec 10 '10 at 18:42
  • The input and desired output demonstrate that I am NOT asking how to copy a hash, I'm transforming it into a new hash based on a function. I would gladly accept edits to the question title that would make this more clear, but it's a tricky problem to express concisely. – prairiedogg Dec 10 '10 at 18:51
  • "Use the keys from a Hash to make a new Hash where each key's value is itself." – zetetic Dec 10 '10 at 19:00
  • I'm still trying to figure out why I'd want a hash that has keys and values be the same. – the Tin Man Dec 10 '10 at 19:55
  • I don't deny that it is pretty silly. It's an argument to a rails method that is showing a select dropdown to the user. I want the display name and input value to be the same and it takes a hash. – prairiedogg Dec 10 '10 at 20:39
  • I thought that an [``](http://www.w3.org/MarkUp/1995-archive/Elements/OPTION.html) would default to returning the content of the tag. Rails overrides that? – the Tin Man Dec 11 '10 at 00:02

2 Answers2

3
h = {'cat' => 'meow', 'dog' => nil}
#=> {"cat"=>"meow", "dog"=>nil}
Hash[h.keys.map{|k| [k,k]}]
#=> {"cat"=>"cat", "dog"=>"dog"}

Here's another, a bit dirty way (and I think it works in 1.8.6):

h.merge(h){|k,v,v| k}
Mladen Jablanović
  • 43,461
  • 10
  • 90
  • 113
  • Excellent answer, but I forgot to mention that I am constrained to ruby 1.8.6, which apparently doesn't have this `Hash` creation syntax. Your answer works perfectly in ruby 1.8.7, but fails in ruby 1.8.6 – prairiedogg Dec 10 '10 at 18:46
  • Ah, I see. Take a look at `backports` gem then, I would expect such feature to be included there. – Mladen Jablanović Dec 10 '10 at 18:53
  • It does work, and points for brevity ... what is "dirty" about it? Is there some pitfall there that I should be concerned about? – prairiedogg Dec 10 '10 at 19:29
  • Not that I know of. Dirty because it's not intuitive and perhaps misusing `merge` method. I think I would go for your initial code (or Michael Kohl's inject-based) if needing 1.8.6 solution that someone else will read. But consider trying backports first. – Mladen Jablanović Dec 10 '10 at 20:26
2
Hash[input.keys.zip(input.keys)] #=> {"cat"=>"cat", "dog"=>"dog"}

Or with inject:

input.keys.inject({}) { |h, k| h[k] = k ; h } #=> {"cat"=>"cat", "dog"=>"dog"}

The second also works in 1.8.6.

Michael Kohl
  • 66,324
  • 14
  • 138
  • 158