Matthew Matt Matthew Matt - 3 months ago 16
Ruby Question

Ruby - Anagram Codes

We have an array of words here:

words = ['demo', 'none', 'tied', 'evil', 'dome', 'mode', 'live',
'fowl', 'veil', 'wolf', 'diet', 'vile', 'edit', 'tide',
'flow', 'neon']

My teacher wrote a program that prints out groups of words that are anagrams. Anagrams are words that have the same exact letters in them but in a different order. The output should look something like this:

["demo", "dome", "mode"]
["neon", "none"]

And here's the solution my teacher showed us:

result = {}

words.each do |word|
key = word.split('').sort.join
if result.has_key?(key)
result[key] = [word]

result.each do |k, v|
puts "------"
p v

I am bit confused how this program works such as when this part was set up
and the part where it says
result[key] = [word]
I know this might be an off question a bit but can anyone one there can explain the solution line by line in a layman's term or in a way a dummy like me would understand.

PS. Sorry newbie here.


See the explanation inline comment:

words.each do |word| #=>  iterate each word in words array. "word" variable will have value at a particular iteration
  key = word
  .split('') #=> splits word, if word is 'demo' on iteration then it will be: `['d', 'e', 'm', 'o']`
  .sort #=> sorts the splitted array, i.e. the array above will be: `['e', 'd', 'm', 'o']`
  .join #=> joins the array sorted in above operation, it will be: 'edmo'. Since this is last operation, it will be returned and saved in `key` variable
  if result.has_key?(key) #=> Check whether result(Hash) already has key: `edmo`, returns true if present
    result[key].push(word) #=> result['edmo'] will give an array value, which can push word in that array
  else #=> false when key is not present in result Hash.
    result[key] = [word] #=> then add key with an array such as: `result['edmo] = ['demo']`

However, you can do the same in idiomatic way:

result ={|h, k| h[k] =[] } #=> if key does not exist then the default value will be an array.

So, the above code will become:

words.each do |word|
  key = word.split('').sort.join
  result[key] << word # no need to validate whether we have key in Hash or not

But, there's a problem with this approach of keeping value as an array. You will have duplicate data in your key if you have duplicate words in our words array. Problem can be solved by just changing array to set:

require 'set'
result ={|h, k| h[k] = }

Now, we're all good.