10

I have a piece of code like this:

my_hash = {}
first_key = 1
second_key = 2
third_key = 3
my_hash[first_key][second_key][third_key] = 100

and the ruby interpreter gave me an error says that:

undefined method `[]' for nil:NilClass (NoMethodError)

So does it mean I cannot use hash like that? or do you think this error might because of something else?

ggorlen
  • 44,755
  • 7
  • 76
  • 106
Allan Jiang
  • 11,063
  • 27
  • 104
  • 165
  • Hints on how to debug your code: http://stackoverflow.com/q/3955688/38765 – Andrew Grimm May 01 '12 at 02:10
  • Allan, you should probably accept one of the answers, unless you consider that your question wasn't fully answered. (Probably either texasbruce's or mine, since we told you a way to achieve what you want. Though I repeat that it's not necessarily good style.) – Gareth McCaughan May 02 '12 at 09:24

4 Answers4

12

Hashes aren't nested by default. As my_hash[first_key] is not set to anything, it is nil. And nil is not a hash, so trying to access one of its elements fails.

So:

my_hash = {}
first_key = 1
second_key = 2
third_key = 3

my_hash[first_key] # nil
my_hash[first_key][second_key]
# undefined method `[]' for nil:NilClass (NoMethodError)

my_hash[first_key] = {}
my_hash[first_key][second_key] # nil

my_hash[first_key][second_key] = {}

my_hash[first_key][second_key][third_key] = 100
my_hash[first_key][second_key][third_key] # 100
Russell
  • 12,261
  • 4
  • 52
  • 75
  • hello thank you, but actually I made my hash to be static (`@@my_hash`), so will the sub hashes be static as well? So the sub_hashes will not be initialized again if I put this piece of code in a loop? – Allan Jiang May 01 '12 at 01:52
  • 5
    @AllanJiang There's no such thing as "static" in Ruby. – Andrew Grimm May 01 '12 at 02:19
8

The way you are using hash is not valid in Ruby, because every single value has to be assigned to a hash first before going to nested hash(I suppose you were from PHP?), but you can use vivified hash:

my_hash = Hash.new{|h,k| h[k]=Hash.new(&h.default_proc)}
first_key = 1
second_key = 2
third_key = 3
my_hash[first_key][second_key][third_key] = 100
p my_hash

#output: {1=>{2=>{3=>100}}}

This is the way you might be comfortable with.

SwiftMango
  • 15,092
  • 13
  • 71
  • 136
2

You can't use hashes like that; my_hash[first_key] is just nil, and then the next indexing operation fails. It's possible to make a hash object that behaves in the way you're looking for -- see http://t-a-w.blogspot.co.uk/2006/07/autovivification-in-ruby.html -- but it's not clear that this is good style.

Gareth McCaughan
  • 19,888
  • 1
  • 41
  • 62
0

You can do something like

class NilClass

  def [] key
    nil
  end

end

in the initializers like nil_overrides.rb and you will able to use nil['xxx'].

Jamal
  • 763
  • 7
  • 22
  • 32
sahin
  • 31
  • 1
  • 2