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.

 
---

Comment

your_ip_is_blacklisted_by sbl.spamhaus.org

---