1

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 ?

6
  • 1
    I think Hash.new(something) is analogous to collections.defaultdict(lambda: something) Commented Apr 15, 2024 at 16:40
  • @Saly07 it's usually better to have one topic per a question, especially when more than one programming language is involved. You should consider asking the Ruby-to-Python conversion in a separate question. Commented Apr 15, 2024 at 16:48
  • Hi Stefan, understand thanks for the advice! I tought since the 2 topics are linked it makes sense to just post them together. My intend in the first place is to understand what is happening excactly in that bit of Ruby code. The Python equivalent is a bonus. Commented Apr 15, 2024 at 16:52
  • 1
    If you don't understand what's happening exactly in that Ruby code – how do you know you need it in Python? ;-) Commented Apr 15, 2024 at 17:03
  • You are correct that this code if for creating infinitely nested Hashes. See these SO Posts: stackoverflow.com/a/25361419/1978251, stackoverflow.com/a/50468286/1978251, stackoverflow.com/a/34621043/1978251, stackoverflow.com/a/49664274/1978251, stackoverflow.com/a/54558830/1978251, stackoverflow.com/questions/13734385/how-does-default-proc-work, ... Commented Apr 15, 2024 at 18:07

1 Answer 1

2

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())
Sign up to request clarification or add additional context in comments.

1 Comment

This is very well explained and very helpful, thanks a lot Holger!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.