views:

79

answers:

1

I am so used to work in PHP with multi-dimensional arrays, where I can assign and initialize a hash by

unset($a); // just to show that there is no variable $a
$a['settings']['system']['memory'] = '1 Gb';
$a['settings']['system']['disk space'] = '100 Gb';

Is there a way to do similar thing in Ruby? Or I need to initialize all dimensions first, and then to assign values. Is it possible to define an advanced Hash which will allow to do what I need? How would you do that?


Update

In addition to the solution proposed by Douglas (see below), I have found a thread on the subject, in which Brian Schröäer has proposed an extension for the Hash class:

class AutoHash < Hash
  def initialize(*args)
    super()
    @update, @update_index = args[0][:update], args[0][:update_key] unless args.empty?
  end

  def [](k)
    if self.has_key?k
      super(k)
    else
      AutoHash.new(:update => self, :update_key => k)
    end
  end

  def []=(k, v)
    @update[@update_index] = self if @update and @update_index
    super
  end
end

It allows to solve the problem when a missing hash item is undesirably created when the item value was only requested, e.g. a['key'].


Some additional references

  1. http://stackoverflow.com/questions/1503671/ruby-hash-autovivification-facets
  2. http://trevoke.net/blog/2009/11/06/auto-vivifying-hashes-in-ruby/
  3. http://www.eecs.harvard.edu/~cduan/technical/ruby/ycombinator.shtml
+4  A: 

Try this:

def hash_with_default_hash
    Hash.new { |hash, key| hash[key] = hash_with_default_hash }
end

a = hash_with_default_hash

If the key doesn't exist, then the result of the block will be used as the default value. In this case, the default value is also a hash which uses hashes as its default values.

Douglas
It works like a charm! Thank you, Douglas
Andrey
There is one more thing to wish - if I just check item value `a['key']`, then a new item with key `key` will be created in case it doesn't exist. How can one avoid such behavior?
Andrey
You're after Hash#has_key? http://ruby-doc.org/core/classes/Hash.html#M002883
Douglas
You are right, I needed it mostly for `if` sentences, where one should use `Hash#has_key?` instead. Trying to change my PHP practices...
Andrey