How can you find all anagrams for one word?

1.7k views Asked by At

I'm trying to get all the anagrams for one word with Ruby but my code doesn't work, I only get three results for the string 'ant'. Any help would be much appreciated.

class Anagram
    attr_reader :word
  def initialize(word)
    @word = word.downcase
  end

  def anagram_maker
    @word_bank = []
    index = @word.length
    minus_one = index - 1

    while (index * minus_one) != 0
      anagram = @word.split('').shuffle.join
      @word_bank << anagram
      index -= 1
    end
    @word_bank = @word_bank.uniq
  end

  def display
    anagram_maker
    if @word_bank.count > 1
      @word_bank.each do |anagram|
        puts anagram
      end
    else
      puts "Not enough letters for an anagram"
    end
  end

end

Not sure what else to try here.

2

There are 2 answers

12
toro2k On BEST ANSWER

Your code is quite un-idiomatic Ruby.

Computing anagrams of a string is a matter of computing the permutations of the characters of the string, and Ruby makes this task quite easy. An example reproducing your Anagram class is:

class Anagram
  def initialize(word)
    @word = word
  end

  def display        
    # In Ruby 2.0 @word.chars will return an array, no need for `to_a`.
    @word.chars.to_a.permutation.map(&:join).uniq.each do |anagram|
      puts anagram
    end
  end
end

anagram = Anagram.new('ant')
anagram.display

# Output
# ant
# atn
# nat
# nta
# tan
# tna

To answer your question: you get only three anagrams because the while loop inside the anagram_maker method is executed three times (the length of the string). Moreover I guess that just shuffling characters is not the proper way of generating permutations, see "Algorithm to generate anagrams" for more information about implementing an anagram algorithm.

0
Sean Larkin On

Also if you wanted a revision of your own code so that you can learn in context of your own writing style you could try this:

class Anagram
    attr_reader :word, :combinations
  def initialize(word)
    @word = word.downcase
    @combinations = ([email protected]).inject(:*)
  end

  def anagram_maker
    @word_bank = []
    index = @word.length
    minus_one = index - 1

    while @word_bank.uniq.count < @combinations
      anagram = @word.split('').shuffle.join
      @word_bank << anagram
    end
    @word_bank = @word_bank.uniq
  end

  def display
    anagram_maker
    if @word_bank.count > 1
      @word_bank.each do |anagram|
        puts anagram
      end
    else
      puts "Not enough letters for an anagram"
    end
  end
end

This is far less efficient than the aforementioned but relevant none-the-less.