Ruby Way to Group Anagrams in String Array

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



Leave a reply



Submit