Odd : a = Hash.new(Hash.new)

  • Thread starter Aldric Giacomoni
  • Start date
A

Aldric Giacomoni

irb(main):086:0> a = Hash.new(Hash.new)
=> {}
irb(main):087:0> a[5]
=> {}
irb(main):088:0> a[5][4] = 3
=> 3
irb(main):089:0> a
=> {}
irb(main):090:0> a[5]
=> {4=>3}
irb(main):091:0> a[5][4]
=> 3
irb(main):092:0> RUBY_DESCRIPTION
=> "ruby 1.8.7 (2008-08-11 patchlevel 72) [i386-mswin32]"

Upon inspection of 'a', it sure seems that it's empty, but upon
inspection of the key, it does have a value attached to it! Can we trust
this? Expected / unexpected behavior ?
 
A

Aldric Giacomoni

Aldric said:
Upon inspection of 'a', it sure seems that it's empty, but upon
inspection of the key, it does have a value attached to it! Can we trust
this? Expected / unexpected behavior ?
# Reminder : a = Hash.new(Hash.new)
irb(main):097:0> a[6] ||= {4 => 4}
=> {4=>3}
irb(main):098:0> a[6]
=> {4=>3}
irb(main):099:0> a
=> {}
irb(main):100:0> a[6]
=> {4=>3}
irb(main):101:0> a[5]
=> {4=>3}

Just for kicks.
 
M

Martin DeMello

# Reminder : a = Hash.new(Hash.new)

The default argument to a hash gets *returned* when the key is not
found, but not added to the hash. The logic is more or less

def [](key)
if self.contains(key):
return self.value_of(key)
else
return default
end

What you want is the block version, which accepts the hash itself and
the key as parameters, and lets you do the right thing, here

a = Hash.new {|hash, key| hash[key] = Hash.new}
a = Hash.new {|hash, key| hash[key] = Hash.new} => {}
a[5] => {}
a
=> {5=>{}}

martin
 
Y

Yossef Mendelssohn

irb(main):086:0> a =3D Hash.new(Hash.new)
=3D> {}
irb(main):087:0> a[5]
=3D> {}
irb(main):088:0> a[5][4] =3D 3
=3D> 3
irb(main):089:0> a
=3D> {}
irb(main):090:0> a[5]
=3D> {4=3D>3}
irb(main):091:0> a[5][4]
=3D> 3
irb(main):092:0> RUBY_DESCRIPTION
=3D> "ruby 1.8.7 (2008-08-11 patchlevel 72) [i386-mswin32]"

Upon inspection of 'a', it sure seems that it's empty, but upon
inspection of the key, it does have a value attached to it! Can we trust
this? Expected / unexpected behavior ?

Maybe this might explain the behavior a bit more clearly:
d =3D Hash.new =3D> {}
a =3D Hash.new(d) =3D> {}
a[5][4] =3D 3 =3D> 3
a =3D> {}
a[5] =3D> {4=3D>3}
a[6] =3D> {4=3D>3}
d
=3D> {4=3D>3}


Notice that the default value for hash a (the other hash) has changed.
And you've already noticed that the hash just appears to have values
when queried specifically, but not when inspected.

You probably want to declare the hash as Hash.new { |h, k| h[k] =3D
{} }
 
A

Aldric Giacomoni

Robert said:
IMHO this solution is even simpler because it does not need the method:

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

Robert - I agree. I like this one better. Feels a little more ruby-ish.
Is there a way to use Proc (or whatever does work) to save this block
and reuse it when creating a new hash ?
Something like :
a = Proc.new {|h,k| h[k] = Hash.new(&h.default_proc)}
b = Hash.new a

Note, I know this is wrong.. It'll just put the proc as the default
value, instead of triggering the proc.
 
J

Jesús Gabriel y Galán

Robert said:
IMHO this solution is even simpler because it does not need the method:

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

Robert - I agree. I like this one better. Feels a little more ruby-ish.
Is there a way to use Proc (or whatever does work) to save this block
and reuse it when creating a new hash ?
Something like :
a = Proc.new {|h,k| h[k] = Hash.new(&h.default_proc)}
b = Hash.new a

Note, I know this is wrong.. It'll just put the proc as the default
value, instead of triggering the proc.



irb(main):001:0> a = Proc.new {|h,k| h[k] = Hash.new(&h.default_proc)}
=> #<Proc:0xb7d81730@(irb):1>
irb(main):002:0> b = Hash.new &a
=> {}
irb(main):003:0> b[1][2] = 3
=> 3
irb(main):004:0> b
=> {1=>{2=>3}}

Jesus.
 
A

Aldric Giacomoni

Jesús Gabriel y Galán said:
irb(main):001:0> a = Proc.new {|h,k| h[k] = Hash.new(&h.default_proc)}
=> #<Proc:0xb7d81730@(irb):1>
irb(main):002:0> b = Hash.new &a
=> {}
irb(main):003:0> b[1][2] = 3
=> 3
irb(main):004:0> b
=> {1=>{2=>3}}

Jesus.

Have a +1 ! I'm not forgetting THAT lesson.
 
R

Robert Klemme

Robert said:
IMHO this solution is even simpler because it does not need the method:

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

Robert - I agree. I like this one better. Feels a little more ruby-ish.
Is there a way to use Proc (or whatever does work) to save this block
and reuse it when creating a new hash ?

The block *is* saved and reused when creating nested Hashes!
Something like :
a = Proc.new {|h,k| h[k] = Hash.new(&h.default_proc)}
b = Hash.new a

Note, I know this is wrong.. It'll just put the proc as the default
value, instead of triggering the proc.

No need for that. Please look at my code again.

Kind regards

robert
 
J

Jesús Gabriel y Galán

Robert said:
IMHO this solution is even simpler because it does not need the method:

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

Robert - I agree. I like this one better. Feels a little more ruby-ish.
Is there a way to use Proc (or whatever does work) to save this block an= d
reuse it when creating a new hash ?

The block *is* saved and reused when creating nested Hashes!
Something like :
a =3D Proc.new {|h,k| h[k] =3D Hash.new(&h.default_proc)}
b =3D Hash.new a

Note, I know this is wrong.. It'll just put the proc as the default valu= e,
instead of triggering the proc.

No need for that. =A0Please look at my code again.

I think he might want to save typing:

a =3D Proc.new {|h,k| h[k] =3D Hash.new(&h.default_proc)}
b =3D Hash.new &a
c =3D Hash.new &a
d =3D Hash.new &a

Maybe this is his use case?

Jesus.
 
R

Robert Klemme

2009/11/5 Jes=FAs Gabriel y Gal=E1n said:
Robert Klemme wrote:

IMHO this solution is even simpler because it does not need the method= :

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

Robert - I agree. I like this one better. Feels a little more ruby-ish.
Is there a way to use Proc (or whatever does work) to save this block a= nd
reuse it when creating a new hash ?

The block *is* saved and reused when creating nested Hashes!
Something like :
a =3D Proc.new {|h,k| h[k] =3D Hash.new(&h.default_proc)}
b =3D Hash.new a

Note, I know this is wrong.. It'll just put the proc as the default val= ue,
instead of triggering the proc.

No need for that. =A0Please look at my code again.

I think he might want to save typing:

a =3D Proc.new {|h,k| h[k] =3D Hash.new(&h.default_proc)}
b =3D Hash.new &a
c =3D Hash.new &a
d =3D Hash.new &a

Maybe this is his use case?

If I wanted to save typing I'd place the whole construction in a method

def cnh # silly name "create nested hash"
Hash.new {|h,k| h[k] =3D Hash.new(&h.default_proc)}
end

a =3D cnh
b =3D cnh
c =3D cnh
d =3D cnh

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
A

Aldric Giacomoni

Robert said:
2009/11/5 Jes�s Gabriel y Gal�n said:
Maybe this is his use case?
If I wanted to save typing I'd place the whole construction in a method

def cnh # silly name "create nested hash"
Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)}
end

a = cnh
b = cnh
c = cnh
d = cnh

Kind regards

robert

Oh sure - be lazier than me. I see how it is. :)
Thanks - Jesus was right.. I was trying to be lazy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,906
Latest member
SkinfixSkintag

Latest Threads

Top