Anagrammatically Ruby
For the past few weeks, I have been looking into Ruby. I’m still learning, but I have been playing with Sinatra and Rails, and along the way, I have conducted some experiments to understand the language a bit better.
Two of the things I like the most with Ruby came very handy for this one: iterators and the way you can chain function calls. Inspired by this, I wanted to solve this problem. The first result was doing it with a Java reflex:
words = {} IO.readlines("/usr/share/dict/words").each do |word| hash = word.chomp.downcase.split(//).sort.join if !words.has_key?(hash) words[hash] = [] end words[hash] << word.chomp end words.values.each do |value| if value.length > 1 puts value.join(",") end end
Symptomatic of this Java-flavoured version is the if !words.has_key?(hash)
, testing for the presence if the hash key to initialize the value with an array. But we’ll get back to that later.
The other Java-looking thing is the test if value.length > 1
for filtering out single values. As you can use closures in Ruby, this piece can be neatly rewritten as follows:
words = {} IO.readlines("words").each do |word| hash = word.chomp.downcase.split(//).sort.join if !words.has_key?(hash) words[hash] = [] end words[hash] << word.chomp end words.values.find_all{|elt| elt.length > 1}.each do |value| puts value.join(",") end
Now is time to get rid of the test for the presence of the key. A little search gives an interesting result indicating how the value can be automatically initialized with an array when the key is not present:
words = Hash.new { |h,k| h[k] = [] } IO.readlines("words").each do |word| words[word.chomp.downcase.split(//).sort.join] << word.chomp end words.values.find_all{|elt| elt.length > 1}.each do |value| puts value.join(",") end
Then, it is just a laugh, you can rewrite the blocks so that they hold on a single line:
words = Hash.new { |h,k| h[k] = [] } IO.readlines("words").each{ |word| words[word.chomp.downcase.split(//).sort.join] << word.chomp } words.values.find_all{|elt| elt.length > 1}.each{ |value| puts value.join(",") }
Pretty cool stuff. This little experiment shows how handy the blocks in Ruby are; again, I’m still learning, but I somehow have the feeling that this could be reduced a bit further — albeit at the expense of readibility.