Home > Software engineering >  Anagram algorithm in python
Anagram algorithm in python

Time:03-31

This program functions like an anagram, the segment below shows a small algorithm which goes through a list of given words that are stored within a list named word_list and compares the items within to a choice word that is inserted by the user.

The first loop iterates through every one of those items within the list and assigns them to word then sets shared_letters(counter to decide whether or not the letters word can be found within choice) to zero before starting to go through shared letters between the two words in order to not overflow the i iterable during the second loop.

The second loop iterates x using the length of word which is stored within word length . Then the loop goes through a conditional if-statement which decides whether the x index letter of sliced word (which is just equal to list(word)) is found within sliced choice (list(choice)). If it is then the counter shared_letters goes up by 1, otherwise it breaks out of the second loop and goes back to the first in order to get a new word.

The looping process has worked fine before with me, but for some reason in this segment of code it just no longer runs the second loop at all, I've tried putting in print statements to check the routes that the program was taking, and it always skipped over the nested for loop. Even when I tried turning it into something like a function, the program just refused to go through that function.


choice = input("Enter a word: ") # User enters a word

# Algorithm below compares the entered word with all the words found in the dictionary, then saves any words found into "sushi" list

for i in range(num_words):      # Word loop, gives iterated word
  word = word_list[i]           # Picks a loop
  shared_letters = 0            # Resets # of shared letters
  for x in range(word_length):  # Goes through the letters of iterated word
    if sliced_word[x] in sliced_choice:  
      shared_letters = x   1
    elif sliced_word[x] not in sliced_choice:
      break    

Here is the complete program just in case you want to get a better idea of it, sorry if the coding looks all jumbled up, I've been trying a lot with this program and I just seem to never reach a good solution.


word_list = ["race","care","car","rake","caring","scar"]
sushi = []

word = ""
sliced_word = list(word)
word_length = len(sliced_word)
  
  
choice_word = ""
sliced_choice = list(choice_word)
choice_length = len(sliced_choice)

shared_letters = 0
num_words = len(word_list)

next_word = False

choice = input("Enter a word: ") # User enters a word 

# Algorithm below compares the entered word with all the words found in the dicitionary, then saves any words found into "sushi" list

for i in range(num_words):  # Word loop, gives iterated word
  word = word_list[i]      # Picks a loop
  shared_letters = 0      # Resets # of shared letters
  for x in range(word_length):  # Goes through the letters of iterated word
    if sliced_word[x] in sliced_choice:  
      # Checks if the letters of the iterated word can be found in the choice word 
      shared_letters = x   1
      
    elif sliced_word[x] not in sliced_choice:
      break # If any of the letters within the iterated word are not within the choice word, it moves onto the next word
  
  if shared_letters == word_length:
    sushi.append(word_list[i])  
    # If all of the letters within the iterated word are found in the choice word, it appends the iterated word into the "sushi" list. Then moves onto the next word in the word_list.
      

CodePudding user response:

You have a number of issues, but I think the biggest is that this search does not account for anagrams that have multiple of the same letter. The easiest way to determine if a word would be an anagram or not would be to see if they each have the same count for each letter.

There is a builtin helper class called Counter from the collections module that can help with this.

>>> from collections import Counter
>>> Counter("care")
Counter({'c': 1, 'a': 1, 'r': 1, 'e': 1})
>>> Counter("race")
Counter({'r': 1, 'a': 1, 'c': 1, 'e': 1})
>>> Counter("care") == Counter("race")
True

Working this into your example, you could refactor like this:

word_list = ["race","care","car","rake","caring","scar"]
sushi = []

for word in word_list:
    if Counter(choice) == Counter(word):
        sushi.append(word)

Now this is kind of slow if we have to make the Counter objects over and over again, so you could choose to store them in a dictionary:

word_list = ["race","care","car","rake","caring","scar"]
word_counters = {word: Counter(word) for word in word_list}
sushi = []

for word, counter in word_counters.items():
    if Counter(choice) == counter:
        sushi.append(word)

If you want to find an imperfect match, say one word is contained in the other, you can use the - operator and test if the lefthand side has any letters left over afterwards:

>>> not (Counter("race") - Counter("racecar"))
True
>>> not (Counter("race") - Counter("bob"))
False

Working that back into the example:

word_list = ["race","care","car","rake","caring","scar"]
word_counters = {word: Counter(word) for word in word_list}
sushi = []

for word, counter in word_counters.items():
    if not (Counter(choice) - counter):
        sushi.append(word)
  • Related