tags:

views:

912

answers:

4

For the sake of convenience I am trying to assign multiple values to a hash key in Ruby. Here's the code so far

myhash = { :name => ["Tom" , "Dick" , "Harry"] }

Looping through the hash gives a concatenated string of the 3 values

**Output**
name : TomDickHarry

**Required Output**
:name => "Tom" , :name => "Dick" , :name => "Harry"

What code must I write to get the required output?

Help is appreciated.

+2  A: 

You've created a hash with the symbol name as the key and an array with 3 elements as the value. So you'll need to iterate thru' myhash[:name] to get the individual array elements.

Rohith
+2  A: 
myhash.each_pair {|k,v| v.each {|n| puts "#{k} => #{n}"}}
#name => Tom
#name => Dick
#name => Harry

The output format is not exactly what you need, but I think you get the idea.

pierr
@pierr, thank you. I have more than 1 keys in that hash and want to iterate over selective keys, for that I am trying Hash[*myhash.select {|k,v| [:name].include?(k)}.flatten] , but getting an error, what am I doing wrong?
Anand
The reason for the error is that flatten is recursive so you end up with 1 long list and not a list of pairs of keys and values.
mikej
+1  A: 

The answers from Rohith and pierr are fine in this case. However, if this is something you're going to make extensive use of it's worth knowing that the data structure which behaves like a Hash but allows multiple values for a key is usually referred to as a multimap. There are a couple of implementations of this for Ruby including this one.

mikej
+1  A: 

re: the issue of iterating over selective keys. Try using reject with the condition inverted instead of using select.

e.g. given:

{:name=>["Tom", "Dick", "Harry"], :keep=>[4, 5, 6], :discard=>[1, 2, 3]}

where we want :name and :keep but not :discard

with select:

myhash.select { |k, v| [:name, :keep].include?(k) }
=> [[:name, ["Tom", "Dick", "Harry"]], [:keep, [4, 5, 6]]]

The result is a list of pairs.

but with reject:

myhash.reject { |k, v| ![:name, :keep].include?(k) }
=> {:name=>["Tom", "Dick", "Harry"], :keep=>[4, 5, 6]}

The result is a Hash with only the entries you want.

This can then be combined with pierr's answer:

hash_to_use = myhash.reject { |k, v| ![:name, :keep].include?(k) }
hash_to_use.each_pair {|k,v| v.each {|n| puts "#{k} => #{n}"}}
mikej