Search code examples
pythonrubydictionaryhashmap

Nested Ruby Hashes in Python


Can anyone please explain what this bit of code does in Ruby ?

x = ->(h, k) { h[k] = Hash.new(&x) }
@abc = Hash.new(&x)

I have searched and couldn't figure out what is exactly happening there. I assume it is meant to create nested Hashes ?

Also, how would this translate if I want to write it in Python ?


Solution

  • With the ruby code, you are creating a new Hash (the Python equivalent would be a dictionary) with a dynamic default value which is defined by the lambda passed to Hash.new. In Python, this could be regarded as an (anonymous) function being passed to the constructor.

    This lambda (with some indirections which shall not be important here) is called each time an undefined key is accessed in the hash. The value returned by the lambda is assumed to be the value of the key. The lambda has also the side effect of adding the default value to the hash.

    This thus works quite similarly to the defaultdict collection in Python.

    Now, the default value will always be a new hash object which again is setup to set and return new hash objects when an undefined key is accessed:

    x = ->(h, k) { h[k] = Hash.new(&x) }
    @abc = Hash.new(&x)
    
    @abc[:a]
    # => {}
    
    @abc[:b]
    # => {}
    
    @abc[:a].equal? @abc[:a]
    => true
    
    @abc[:a].equal? @abc[:b]
    => false
    
    @abc[:custom] = 123
    @abc[:x][:y][:z] = 'abc'
    @abc
    # => {:a=>{}, :b=>{}, :custom=>123, :x=>{:y=>{:z=>"abc"}}}
    

    I believe the equivalent Python data structure would be something like this defaultdict:

    from collections import defaultdict
    
    x = lambda defaultdict(lambda: x())
    abc = defaultdict(lambda: x())