Ruby way to group anagrams in string array
Like that:
a = ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', 'scream']
a.group_by { |element| element.downcase.chars.sort }.values
Output is:
[["cars", "racs", "scar"], ["for"], ["potatoes"], ["four"], ["creams", "scream"]]
If you want to you can turn this one-liner to a method of course.
How to group anagrams together of a array in Ruby
What about this:
def anagrams(ary)
h = Hash.new([])
ary.each.with_index { |el, i| h[el.downcase.chars.sort.join] += [i] }
h.map { |key, indexes| indexes.map { |i| ary[i] } }
end
The function saves the indexes in a hash and then returns the corresponding elements.
This approach scans the array at most twice, therefore it's O(n). Even if it is not particularly elegant, it is quite fast.
How to group anagrams in a string into an array
The problem is that you don't assign the resulting array back to anagrams_hash
, i.e., you take the array from the hash and then you append the word to that array, but never write the resulting array back to the hash. This causes a problem when the key does not exist in the hash and you get the default element instead. The fix would be, e.g.,
words.each {|word| anagrams_hash[word.chars.sort.join] += [ word ] }
How to sort array of words into arrays of anagrams in Ruby?
You could easily do it like this:
def combine_anagrams(words)
anagrams={}
words.each do |word|
anagrams[word.downcase.split('').sort.join] ||=[]
anagrams[word.downcase.split('').sort.join] << word
end
anagrams.values
end
Ruby Anagram Using String#sum
Unfortunately I don't think String#sum
is a robust way to solve this problem.
Consider:
"zaa".sum # => 316
"yab".sum # => 316
Same sum, but not anagrams.
Instead, how about grouping them by the sorted order of their characters?
words = %w[cars scar for four creams scream racs]
anagrams = words.group_by { |word| word.chars.sort }.values
# => [["cars", "scar", "racs"], ["for"], ["four"], ["creams", "scream"]]
How can I simplify or clean up this anagram method?
test_words.group_by{|w| w.each_char.sort}.values
would give
[
["cars", "racs", "scar"],
["for"],
["potatoes"],
["four"],
["creams", "scream"]
]
Input is array of words-Output should be Array of Arrays that groups anagrams.
x.group_by{|s| s.downcase.chars.sort}.values
# => [["cars", "racs", "scar"], ["for"], ["potatoes"], ["four"], ["creams", "scream"]]
Ruby - Anagram Codes
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.
Alphabetically sorting an array within an array in Ruby?
You need to map this array and sort (map(&:sort)
)
def group_anagrams(ary)
ary.group_by { |s| s.chars.sort }.values.map(&:sort)
end
ary = ["eat", "tea", "tan", "ate", "nat", "bat"]
group_anagrams(ary)
# => [["ate", "eat", "tea"], ["nat", "tan"], ["bat"]]
Related Topics
How to Start the Ruby Debugger on Exception
Why Does Openuri Treat Files Under 10Kb in Size as Stringio
How to Use Ruby " Case ... When " with Inequalities
Rails: How to Get a File Extension/Postfix Based on the Mime Type
How Does MACports Install Packages? How to Activate a Ruby Installation Done via MACports
Certificate Verify Failed in "Gem Install Foundation"
How to Get the Current Route in Rails
Using Calendar_Date_Select with Rails 3
Ruby Regex- Does Gsub Store What It Matches
How to Get My Aws Lambda to Access Gems Stored in Vendor/Bundle
Cucumber + Webrat + Selenium Guide
How to Split a String into Only Two Parts, by the Last Occurrence of the Split Char
<Rubygems> How to Change Gem Environment Settings
How to Check If There's a Nil Set or Not in an Array
What Does the Regular Expression [\W-] Mean
How to Make Users Automatically Follow Admin User on Sign Up