Hash.new(confusion)

T

Trans

irb(main):006:0> def r
irb(main):007:1> @r ||= Hash.new({})
irb(main):008:1> end
=> nil
irb(main):009:0> r[:a]
=> {}
irb(main):010:0> r[:b][:c] = 10
=> 10
irb(main):011:0> r
=> {}
irb(main):012:0> r[:b]
=> {:c=>10}
irb(main):013:0>

Please explain how r is empty but r[:b] exists. Thank You.

T.
 
J

Joel VanderWerf

Trans said:
irb(main):006:0> def r
irb(main):007:1> @r ||= Hash.new({})
irb(main):008:1> end
=> nil
irb(main):009:0> r[:a]
=> {}
irb(main):010:0> r[:b][:c] = 10
=> 10
irb(main):011:0> r
=> {}
irb(main):012:0> r[:b]
=> {:c=>10}
irb(main):013:0>

Please explain how r is empty but r[:b] exists. Thank You.

T.

Try

p r.default

and you'll see what's going on.
 
G

Gennady Bystritsky

If you specify a parameter for Hash.new the SAME object will be used
for any default value (see documentation). If you modify it, it will
be modified for all default values afterwards. Try to see what the
value will be returned for r[:a] if you do it again. I bet it will be
{:c => 10}. As well as for r[:c], r[10] and so on.

Gennady.
 
M

Mitch Tishmack

r is independent of r[:b]. r[:b] is a hash with a value containing
another hash/key value.

ie {:b => {:c => 10}} NOT {:b => 10, :c = 10}. If I understand your
confusion correctly.

irb(main):001:0> def r
irb(main):002:1> @r ||= Hash.new({})
irb(main):003:1> end
=> nil
irb(main):004:0> r[:a]
=> {}
irb(main):005:0> r.empty?
=> true
irb(main):006:0> r[:a] = 1
=> 1
irb(main):007:0> r.empty?
=> false
irb(main):008:0> r[:b][:c] = 10
=> 10
irb(main):009:0> r
=> {:a=>1}
irb(main):010:0> r[:b]
=> {:c=>10}
irb(main):011:0> (r[:b])[:c]
=> 10
irb(main):012:0> r[:a]
=> 1
irb(main):013:0> r.size
=> 1
irb(main):014:0> r[:b].size
=> 1
irb(main):015:0> r[:b][:d] = 300000
=> 300000
irb(main):016:0> r[:b].size
=> 2
irb(main):018:0> r
=> {:a=>1}
irb(main):019:0> r[:b]
=> {:d=>300000, :c=>10}

Or did I completely miss your point?

Mitch
 
D

Dave Burt

...
Please explain how r is empty but r[:b] exists. Thank You.

# To summarize:
h = Hash.new({})
h[1][2] = 3
h #=> {}
h.default #=> {2=>3}

So you've added to the default object. It might be helpful to note another
wrong way to do this:
h = Hash.new { {} }
h[1][2] = 3
h #=> {}
h.default #=> {}

Different, because default now returns a new hash every time.

But, to answer the implied question, "what is the code that will do what I
intend?" there are a few ways to do this:

# Just one level of magic new hashes
h = Hash.new {|hash, key| hash[key] = {} }
h[1][2] = 3
h #=> {1=>{2=>3}}
h[1][2][3] = 4 # Error (calling []= on nil)

# Auto-vivifying hash: using proc
auto_vivivy_hash = proc {|hash, key| hash[key] = Hash.new
&auto_vivivy_hash }
h = Hash.new &auto_vivify_hash
h[1][2][3] = 4 #=> {1=>{2=>{3=>4}}}

# Auto-vivifying hash: using Hash subclass
class X < Hash
def default(key = nil)
self[key] = self.class.new
end
end
h = X.new #=> {}
h[1][2][3] = 4
h #=> {1=>{2=>{3=>4}}}

Cheers,
Dave
 
D

David A. Black

Hi --

irb(main):006:0> def r
irb(main):007:1> @r ||= Hash.new({})
irb(main):008:1> end
=> nil
irb(main):009:0> r[:a]
=> {}
irb(main):010:0> r[:b][:c] = 10
=> 10
irb(main):011:0> r
=> {}
irb(main):012:0> r[:b]
=> {:c=>10}
irb(main):013:0>

Please explain how r is empty but r[:b] exists. Thank You.

r[:b] doesn't exist, so instead, you get the hash's default value
(which is what is returned for non-existent keys).


David
 

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

No members online now.

Forum statistics

Threads
474,431
Messages
2,571,677
Members
48,796
Latest member
Greg L.

Latest Threads

Top