Alex Feinman
Alex Feinman

Reputation: 5563

Compact way to add new values to a map of maps?

I've written a tool to count frequency of word pairs in a text, such that for each time word B follows word A, the count of words[A][B] is incremented.

In perl, the hash and hash of hashes gets automatically instantiated the first time you try to access it, which makes the code simple. In Javascript, it seems that you must first create the innards, which makes the code longer.

In Coffeescript, this functions:

class Adder
  ...
  addPair: (word1, word2) -> 
    @count[word1] = {} if not @count[word1]? 
    @count[word1][word2] = 0 if not @count[word1][word2]? 
    ++@count[word1][word2]

but it's two extra lines of 'defensive' code. Is there a way to do this more compactly, so I can maintain less code?

(Putting it in a trinary statement doesn't really make it more compact, just fewer characters for the same amount of logic.)

Upvotes: 1

Views: 56

Answers (1)

epidemian
epidemian

Reputation: 19229

You can reduce the verbosity of those lines by using the or= operator (or ?=, but it's not necessary in these case):

addPair: (word1, word2) -> 
  @count[word1] or= {} 
  @count[word1][word2] or= 0 
  @count[word1][word2] += 1

You can also golf those two initialization lines into one (though i think this results in less readable code):

addPair: (word1, word2) -> 
  (@count[word1] or= {})[word2] or= 0 
  @count[word1][word2] += 1

By the way, supporting this kind of automatic object creation is known as autovivification, and has been discussed on the CoffeeScript issues. Also, Coco, a CS-derived language, has it :)

Upvotes: 1

Related Questions