29

I have an array of hashes to write a generic checker for, so I want to pass in the name of a key to be checked. The hash was defined with keys with symbols (colon prefixes). I can't figure out how to use the variable as a key properly. Even though the key exists in the hash, using the variable to access it results in nil.

In IRB I do this:

>> family = { 'husband' => "Homer", 'wife' => "Marge" }
=> {"husband"=>"Homer", "wife"=>"Marge"}
>> somevar = "husband"
=> "husband"
>> family[somevar]
=> "Homer"
>> another_family  = { :husband => "Fred", :wife => "Wilma" }
=> {:husband=>"Fred", :wife=>"Wilma"}
>> another_family[somevar]
=> nil
>>

How do I access the hash key through a variable? Perhaps another way to ask is, how do I coerce the variable to a symbol?

Leonard
  • 13,269
  • 9
  • 45
  • 72

5 Answers5

49

You want to convert your string to a symbol first:

another_family[somevar.to_sym]

If you want to not have to worry about if your hash is symbol or string, simply convert it to symbolized keys

see: How do I convert a Ruby hash so that all of its keys are symbols?

Community
  • 1
  • 1
gateblues
  • 786
  • 7
  • 8
7

You can use the Active Support gem to get access to the with_indifferent_access method:

require 'active_support/core_ext/hash/indifferent_access'
> hash = { somekey: 'somevalue' }.with_indifferent_access
 => {"somekey"=>"somevalue"}
> hash[:somekey]
 => "somevalue"
> hash['somekey']
=> "somevalue"
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
suddenenema
  • 351
  • 1
  • 5
  • 1
    This uses [ActiveSupport Core Extensions](http://edgeguides.rubyonrails.org/active_support_core_extensions.html), which is the proper way to cherry-pick specific extensions. – the Tin Man Aug 27 '14 at 23:14
3

Since your keys are symbols, use symbols as keys.

> hash = { :husband => 'Homer', :wife => 'Marge' }
 => {:husband=>"Homer", :wife=>"Marge"}
> key_variable = :husband
 => :husband
> hash[key_variable]
 => "Homer"
Ray
  • 713
  • 5
  • 11
  • This might work in some circumstances, but in my case I'm passing them in as parameters, and Trollop (argument parsing gem) won't accept a symbol as a default value. – Leonard Aug 28 '14 at 00:01
0

If you use Rails with ActiveSupport, then do use HashWithIndifferentAccess for flexibility in accessing hash with either string or symbol.

family = HashWithIndifferentAccess.new({
  'husband' => "Homer", 
  'wife' => "Marge"
})

somevar = "husband"
puts family[somevar]
#Homer

somevar = :husband
puts family[somevar]
#Homer
Ken Ratanachai S.
  • 3,307
  • 34
  • 43
-1

The things that you see as a variable-key in the hash are called Symbol is a structure in Ruby. They're primarily used either as hash keys or for referencing method names. They're immutable, and Only one copy of any symbol exists at a given time, so they save memory.

You can convert a string or symbol with .to_sym or a symbol to string with .to_s to illustrate this let me show this example:

strings = ["HTML", "CSS", "JavaScript", "Python", "Ruby"]
symbolArray = [:HTML, :CSS, :JavaScript, :Python, :Ruby]
# Add your code below!

symbols = Array.new
strings.each {|x|
 symbols.push(x.to_sym)
}

string = Array.new
symbolArray .each {|x|
 string.push(x.to_s)
}
print symbols
print string

the result would be:

[:HTML, :CSS, :JavaScript, :Python, :Ruby]
["HTML", "CSS", "JavaScript", "Python", "Ruby"]

In ruby 9.1 you would see the symbols with the colons (:) in the right instead:

movies = { peter_pan: "magic dust", need_4_speed: "hey bro", back_to_the_future: "hey Doc!" }

I just wanted to make this point a litter more didactic so who ever is reading this can used.

One last thing, this is another way to solve your problem:

movie_ratings = {
  :memento =>  3,
  :primer => 3.5,
  :the_matrix => 3,

}
# Add your code below!

movie_ratings.each_key {|k| 
puts k.to_s
}

result:

memento
primer
the_matrix
Jesus Gonzalez
  • 127
  • 2
  • 2