Thursday, July 13, 2006

Autovivification in Ruby

W00t, one of my favourite Perl features can be ported to Ruby in just a single line of code. As everyone knows, in Perl it's possible to write:
$x{a}{b}{c}{d} = "e";
And all intermediate-level hashtables will be created automagically. This is often extremely useful. On the other hand in lesser languages like Python or Java the only way to set a value in a nested hash is to create intermediate-level hashtables by hand:
x={}
x["a"] = {}
x["a"]["b"] = {}
x["a"]["b"]["c"] = {}
x["a"]["b"]["c"]["d"] = "e"
This may be a small thing, but multi-level hashes are used so often that one actually misses this functionality. For long I thought that Ruby doesn't have autovivification. And well, it doesn't have the full Perl thing, but it can get reasonably close with just this small definition:
def autovivifying_hash
   Hash.new {|ht,k| ht[k] = autovivifying_hash}
end
And now you can say:
x = autovivifying_hash
x["a"]["b"]["c"]["d"] = "e"
And that's going to be good enough most of the time :-)

4 comments:

  1. Anonymous12:12

    Thank you, I was just looking for this. Perfect solution for me :)

    ReplyDelete
  2. I find this solution more elegant:

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

    ReplyDelete
  3. Anonymous17:13

    In perl, you can also do
    x{1}{'hello'}[4]{7}=5 ... I suppose doing this in ruby would be worse ...

    ReplyDelete
  4. Anonymous: You pretty much never autovivify arrays like that by key assignment in practice, you only do that by pushing at the end of them.

    Perl's syntax for push-autovivify is horrible.

    Something like: push @{$x{1}{hello}}, {7 => 5}

    ReplyDelete