5

Lets say I have a Hash called person whose key is name and value is a hash having keys 'age' and 'hobby'. An entry in the hash person would look like

=> person["some_guy"] = {:hobby => "biking", :age => 30}

How would I go about specifying the default for the hash 'person'? I tried the following

=> person.default = {:hobby => "none", :age => 20}

but it doesn't work.

EDIT:

I was setting one attribute and expecting others to be auto-populated. For eg.

=> person["dude"][:age] += 5

and this is what I was seeing

=> person["dude"]
=> {:hobby => "none", :age => 25}

which is fine. However, typing person at the prompt, I get an empty hash.

=> person
=> {}

However, what I was expecting was

=> person
=> {"dude" => {:hobby => "none", :age => 25}}
kshenoy
  • 1,726
  • 17
  • 31
  • "It doesn't work" isn't exactly a very helpful description. What is the output you are seeing? What is the output you are expecting? What are you doing to get that output? What is the error message? The code you posted *should* work, and if you copy&paste it and run it, then it indeed *does* work! – Jörg W Mittag Jun 06 '12 at 08:13
  • @JörgWMittag The question does seem very vague when read from someone else's perspective. Hope, the edits help. – kshenoy Jun 07 '12 at 16:58
  • @CodeGnome Thanks for pointing that out. Found that some of the older questions had been answered. – kshenoy Jun 07 '12 at 17:01

3 Answers3

8

Why It May Not Work for You

You can't call Hash#default if an object doesn't have the method. You need to make sure that person.is_a? Hash before it will work. Are you sure you don't have an array instead?

It's also worth noting that a hash default doesn't populate anything; it's just the value that's returned when a key is missing. If you create a key, then you still need to populate the value.

Why It Works for Me

# Pass a default to the constructor method.
person = Hash.new({hobby: "", age: 0})
person[:foo]
=> {:hobby=>"", :age=>0}

# Assign a hash literal, and then call the #default method on it.
person = {}
person.default = {hobby: "", age: 0}
person[:foo]
=> {:hobby=>"", :age=>0}

What You Probably Want

Since hash defaults only apply to missing keys, not missing values, you need to take a different approach if you want to populate a hash of hashes. One approach is to pass a block to the hash constructor. For example:

person = Hash.new {|hash,key| hash[key]={hobby: nil, age:0}}
=> {}

person[:foo]
=> {:hobby=>nil, :age=>0}

person[:bar]
=> {:hobby=>nil, :age=>0}

person
=> {:foo=>{:hobby=>nil, :age=>0}, :bar=>{:hobby=>nil, :age=>0}}
Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
2

You can specify a hash's default value on instantiation by passing the default value to the .new method:

person = Hash.new({ :hobby => '', :age => 0 })
Samy Dindane
  • 17,900
  • 3
  • 40
  • 50
  • The default value does not get duplicated. I.e. the top-level hash will have the same value everywhere. h = Hash.new(Hash.new(0)) h[1][0] # => 0 h[0][0] = 123 h[1][0] # => 123 – wedesoft Feb 19 '16 at 11:26
0

You can use Hash#default_proc to initialise a hash with default values dynamically.

h = Hash.new
h.default_proc = proc do |hash, key|
  hash[key] = Hash.new(0) unless hash.include? key
end
h[0][0] # => 0
h[1][0] # => 0
h[0][0] = 1
h[0][0] # => 1
h[1][0] # => 0
wedesoft
  • 2,781
  • 28
  • 25