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"]
(etc)
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].push(word)
else
result[key] = [word]
end
end
result.each do |k, v|
puts "------"
p v
end
I am bit confused how this program works such as when this part was set up result[key].push(word)
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']`
end
end
However, you can do the same in idiomatic way:
result = Hash.new{|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
end
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 = Hash.new{|h, k| h[k] = Set.new }
Now, we're all good.