Double assignation in a hash

hi !

I’m new to ruby, i’d like to know if it is possible to make the
following kind of assignation in a hash, like i used to do in php :

a={}
a[:b][:c]=“value”

the goal for me is to create a hash by iterating on keys, like

hash={}
[a,b,c].each do |k1|
[d,e,f].each do |k2|
hash[k1][k2] = afunction(k1,k2)
end
end

this last code lead to a nil.[] error

Could you help me ? .

On Jun 4, 2008, at 7:23 PM, nico Itkin wrote:

hash={}
[a,b,c].each do |k1|
[d,e,f].each do |k2|
hash[k1][k2] = afunction(k1,k2)
end
end

this last code lead to a nil.[] error

Could you help me ? .

Your problem is that a[:b] is not a hash. You can get this effect by
defining a default for the hash ‘a’ like so:

irb> a = Hash.new {|h,k| h[k] = {} }
=> {}
irb> a[:b][:c] = ‘value’
=> “value”
irb> a
=> {:b=>{:c=>“value”}}

The block supplied to Hash.new is called with the hash and the key
when the key doesn’t exist. So the effect is as if you had:

a = {}
a[:b] = {}
a[:b][:c] = ‘value’

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

On Thu, Jun 5, 2008 at 1:23 AM, nico Itkin [email protected]
wrote:

hi !

I’m new to ruby, i’d like to know if it is possible to make the
following kind of assignation in a hash, like i used to do in php :

a={}
a[:b][:c]=“value”

For arbitrary hash nesting, try this:

irb(main):023:0> a = Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}
irb(main):024:0> a[1][2][3][4] = “hello”
irb(main):025:0> a
=> {1=>{2=>{3=>{4=>“hello”}}}}
irb(main):026:0> a[1][2][3][4]
=> “hello”

Hope this helps,

Jesus.

On Thu, Jun 05, 2008 at 08:23:53AM +0900, nico Itkin wrote:

hash={}
[a,b,c].each do |k1|
[d,e,f].each do |k2|
hash[k1][k2] = afunction(k1,k2)
end
end

this last code lead to a nil.[] error

Could you help me ? .

You may find this of interest:

http://redcorundum.blogspot.com/2007/05/just-nifty-meta-meta-tidbit.html

–Greg

Jesús Gabriel y Galán wrote:

For arbitrary hash nesting, try this:

irb(main):023:0> a = Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}
irb(main):024:0> a[1][2][3][4] = “hello”
irb(main):025:0> a
=> {1=>{2=>{3=>{4=>“hello”}}}}
irb(main):026:0> a[1][2][3][4]
=> “hello”

Or this (longer but clearer IMO):

a = {}
a[1] = {}
a[1][2] = {}
a[1][2][3] = {}
a[1][2][3][4] = “hello”

print a[1][2][3][4] # “hello”

On Sun, Jun 8, 2008 at 10:25 PM, nico Itkin [email protected]
wrote:

Thanks evebody for yours answers, helps a lot :slight_smile: !

Jesús : looks fantastic, but could you give me fex explanation how it
works?

a = Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}

is this a way to override the method new for the object a?

You’re doing so by passing the following block but then i’m lost, do you
have any links to share which detail that ?

Hash.new receives a block, which is executed whenever you try to access
a non-existing key. In the block you can assign a value to the key in
the hash.
The value that we assign above is a hash. If we did this:

a = Hash.new {|h,k| h[k] = Hash.new}

Then we would achieve a two-level hash, but the second level hash,
wouldn’t be able to assign a next level hash to a non-existing key,
because
a block wasn’t provided.

Hash has a default_proc variable that contains the block (in proc form)
that was passed to the constructor, so if we assign this proc as the
block
for the constructor, we get a hash that can assign a hash to a
non-existing key,
in a recursive way, cause each hash will pass its default proc to the
hash
created in the constructor block.

So many words that I don’t know if I made myself clear…

Jesus.

Thanks evebody for yours answers, helps a lot :slight_smile: !

Jesús : looks fantastic, but could you give me fex explanation how it
works?

a = Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}

is this a way to override the method new for the object a?

You’re doing so by passing the following block but then i’m lost, do you
have any links to share which detail that ?

Nico (so much to learn…)