Anagram algorithm in python - python

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.

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

Write a function longest_word that asks the user for words and returns the longest word entered by the user

Write a function longest_word that asks the user for words and returns the longest word entered by the user. It should stop when the user hits return without typing a word. If multiple words have the same maximum length, return the first word entered by the user. If the user quits before entering any words, return “No words were entered”. This function should use a searching loop. (Hint: remember that the len function returns the length of a string.)
def longest_word():
word = input("enter a word")
if word == "":
return "No words were entered"
max = 0
while len(word) > max :
max = len(word)
new_word = input("enter a word")
if len(new_word) <= len(word):
print(word)
else:
print(new_word)
longest_word()
I understand that I need to iterate the while loop until the user enters without typing any words, but I do not know how to write the corresponding code.
The logic of your code had some flaws.
You need to run the while loop until the input is "" or an empty string and the len(word)>max needs to be inside an if statement. This is because the input value decides whether to break the loop or continue it, the difference in lengths just determines the result.
The returned word should be the longest one(only). But the block:
if len(new_word) <= len(word):
print(word)
else:
print(new_word)
Prints every entered word that is longer than the previous one.
3. You need to change the value of the previous word or the longest word every time a longer word is entered so that it is updated, not just the value of the length.
The code might look like:
def longest_word():
word = input("enter a word")
if word == "":
return "No words were entered"
max = 0 # This variable is not exactly required
longest = word # this variable stores the longest word(currently)
new_word = None # This assignment is for checking for empty strings
while new_word != "" :
max = len(word)
new_word = input("enter a word")
if len(new_word) >= len(longest): # If the entered word is longer, change
# value of the longest word
longest = new_word
print(longest) # Print the longest word.
longest_word()
This is not necessary but avoid naming variables the same as keywords as it often causes a confusion
Some key points of what this function needs to do:
It needs to return the longest word, not print it.
It needs to keep track of the longest word seen so far (so it can return it when it's done). Keeping track of the length of the longest word is not sufficient.
Here's how I might write it:
def longest_word():
longest = ""
while True:
word = input("enter a word")
if not word:
return longest or "No words were entered"
if len(word) > len(longest):
longest = word
Note that the return line immediately ends the loop once no word is entered, and the or statement handles the case where nothing was entered prior to that point.
The remaining if statement ensures that longest is the longest word seen so far.

How to find words without certain letters in them and certain letters in the same place that are in specified length

I want to make a hangman game that randomises the word each time you guess a letter, but keeps the wrong letters wrong and the ones you guessed at the same place in the new word. (Like if your word was cat in the beginning and you guessed the 'a'; now the word can be hat.)
I feel like I want to implement too many statements in a while loop and it breaks somehow.
I have this function
def RevealLetters(inputLetter):
LetterPositons.clear()
global WrongGuessCounter
for pos,char in enumerate(Word):
if(char == inputLetter):
LetterPositons.append(pos)
for x in LetterPositons:
if MaskedWord[x] == "_":
MaskedWord[x] = inputLetter
if len(LetterPositons) == 0:
WrongGuessCounter += 1
WrongLetters.append(inputLetter)
Which adds the wrongly guessed letter to a list and those letters should not be used again.
Then in another function I have this while loop which should be able to go thru the list of words and select words that are a specified length (the length was set in another function)
def RandomiseWord():
global Word
print("Randomising Word!")
Word = random.choice(WordBank)
LetterPositons.clear()
while (len(Word) != len(MaskedWord)) and (all(letter in Word for letter in WrongLetters)) :
Word = random.choice(WordBank)
but this somehow gives me words that either contain a letter from the list or a word with a different length.
I tried using if statements inside the while but it broke it further.
And lastly how may I check for words that have the same letters in the same place?
The issue was in my while. it has to be the "Or" statement.
in the end the randomise function looked like this:
def RandomiseWord(): #Randomises the word to add a challange to the game
global Word
global MaskedWord
global WrongLetters
print("Randomising Word!")
Word = random.choice(WordBank)
LetterPositons.clear()
while len(Word) != (len(MaskedWord)+1) or all(letter in Word for letter in WrongLetters) or not all(CheckWord()) :
Word = random.choice(WordBank)
and for finding words with letters in the same place I used:
def CheckWord(): #checks if the word contains the letters in the same place as the hidden one
global MaskedWord
global Word
Match = []
LetterList = list(Word)
LetterList.pop()
for x in range(len(MaskedWord)):
if MaskedWord[x] == "_":
continue
elif MaskedWord[x] == LetterList[x]:
Match.append(True)
else:
Match.append(False)
return Match

Python Question Relating to Finding Anagram from Dictionary

I am struggling with this project that I am working on.
Edit: I want the program to find 2 words from the dictionary that are the anagram of the input word(s). The way I wanted to approach this program is by using counter(input()) and then looping through the dictionary content twice (finding first word anagram then the next). The loop would take every word from the dictionary, counter(that word) and see if it is <= counter(input word). Once the program finds first anagram, it adds that word to candidate and proceeds to second loop to find the second word.
To put to simple words, if I input a word (or a phrase), I would like the program to run through a dictionary text file (which I have saved) and find two words from the dictionary that becomes anagram to my input. For instance, if I input "dormitory" the program output should be "dirty room" and if input "a gentleman", output "elegant man". Here is what I have done so far:
from pathlib import Path
from collections import Counter
my_dictionary = open(Path.home() / 'dictionary.txt')
my_words = my_dictionary.read().strip().split('\n')
my_dictionary.close()
letter_number = 0
my_word = []
print('Please type in your phrase:')
word = input()
word = word.replace(" ","")
word_map = Counter(word.lower())
for a_word in my_words:
test = ''
candidate = ''
test_word = Counter(a_word.lower())
for letter in test_word:
if test_word[letter] <= word_map[letter]:
test += letter
if Counter(test) == test_word:
candidate += a_word.lower()
for a_word in my_words:
test = ''
test_word = Counter(a_word.lower())
for letter in test_word:
if test_word[letter] <= word_map[letter]:
test += letter
if Counter(test) == test_word:
candidate += a_word.lower()
if Counter(candidate) == word_map:
my_word.append(candidate)
print(my_word)
For some reason I am getting nothing from the output.
I cannot get any result after I put my input.
I also have tried to use del. command for getting rid of the word counter of first word from dictionary then proceed to find a second word from the dictionary but that didn't work either.
In summary, there must be some wrong place in the codes that flaws the program to not give any output.
Please help me figure out my mistake and error.
Thanks in advance.
Code can be optimized as follows:
# script.py
from pathlib import Path
from collections import Counter
filename = 'dictionary.txt'
my_words = Path.home().joinpath(filename).read_text().strip().splitlines()
word = input('Please type in your phrase:\n').replace(" ","")
word_counter = Counter(word.lower())
def parse(my_words=my_words):
matches = []
for a_word in my_words:
a_word_counter = Counter(a_word.lower())
if all(c <= word_counter[w] for c in a_word_counter.values()):
matches.append(a_word)
return matches
def exactly_parse(my_words=my_words):
return [w for w in my_words if Counter(w) == word_counter]
my_word = parse()
print(my_word)
Let's say content of dictionary.txt:
$ cat dictionary.txt
how
are
you
fine
thanks
input word is how
What's the expected output? how
$ python script.py
Please type in your phrase:
how
['how']
$ python script.py
Please type in your phrase:
thanksyou
['you', 'thanks']

Selecting randomly from a list with a specific character

So, I have a text file (full of words) I put into a list. I want Python 2.7 to select a word from the list randomly, but for it to start in a specific character.
list code:
d=[]
with open("dic.txt", "r") as x:
d=[line.strip() for line in x]
It's for a game called Shiritori. The user starts with saying any word in the English language, ie dog. The program then has to pick another word starting with the last character, in this case, 'g'.
code for the game:
game_user='-1'
game_user=raw_input("em, lets go with ")
a1=len(game_user)
I need a program that will randomly select a word beginning with that character.
Because your game relies specifically upon a random word with a fixed starting letter, I suggest first sorting all your words into a dictionary with the starting letter as the key. Then, you can randomly lookup any word starting with a given letter:
d=[]
lookup = {}
with open("dic.txt", "r") as x:
d=[line.strip() for line in x]
for word in d:
if word[0] in lookup:
lookup[word[0]].append(word)
else:
lookup[word[0]] = [ word ]
now you have a dict 'lookup' that has all your words sorted by letter.
When you need a word that starts with the last letter of the previous word, you can randomly pick an element in your list:
import random
random_word = random.choice(lookup[ game_user[-1] ])
In order to get a new list of all the values that start with the last letter of the user input:
choices = [x in d if x[0] == game_user[-1]]
Then, you can select a word by:
newWord = random.choice(choices)
>>> import random
>>> with open('/usr/share/dict/words') as f:
... words = f.read().splitlines()
...
>>> c = 'a'
>>> random.choice([w for w in words if w.startswith(c)])
'anthologizing'
Obviously, you need to replace c = 'a' with raw_input("em, lets go with ")
You might get better use out of more advanced data structures, but here's a shot:
words_dict = {}
for row in d:
# Gives us the first letter
myletter = row[0]
if myletter not in words_dict:
words_dict[myletter] = []
words_dict[myletter].append(row)
After creating a dictionary of all letters and their corresponding words, you can then access any particular set of words like so:
words_dict['a']
Which will give you all the words that start with a in a list. Then you can take:
# This could be any letter here..
someletter = 'a'
newword = words_dict[someletter][random.randint(0,len(words_dict[someletter]-1))]
Let me know if that makes sense?

Caesar Cipher Spacing Error

I am currently programming the Caesar Cipher.
I created a list of the alphabets
It simply asks for a sentence
Gets the index position of each letter in the sentence in corresponding to the alphabet list,
Adds the offset onto each offset using a while loop, creating a new index
Prints out the corresponding alphabet list index with new index which makes a coded word.
Therefore creating a coded sentence
The problem is that the alphabet list does not contain spaces, so I get an error when I try to make a sentence (because it is separated by spaces), only single words/letters work...
CODE HERE:
#Creating Lists
alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
#Unpickling Dictionary
unpickle_codedwords = open("CWs.txt", "rb")
codedwords = pickle.load(unpickle_codedwords)
unpickle_codedwords.close()
###############################################################
""" #
IMPROVMENTS: #
Spaces/Sentences dont work <-- bob is a boy (ERROR) #
""" #
###############################################################
loop = 0#Using this to make my program loop continously
while loop == 0:
choice=int(input("What would you like to do?\n1)Code a word\n2)Decode a word\n3)Print the coded words list\n4)Quit the program\n5)Clear Coded Words List\n>>>"))#Asking for choice from user
if choice ==1:#If the choice selected was 1:
word=input("Enter the word you want to code\n>>>")
offset=int(input("Enter the offset below\n>>>"))
if word.isalpha() ==True:#checking alphabet only
for letter in word.lower(): # getting index of everysingle letter and converting it to lowercase
index=alphabet.index(letter)
index=index+offset#adding the index to the offset to create new index
while index>25:#if index is more than 25 i have to while loop it
index=index-26#creatingn the new index
codedwords.append([alphabet[index]])#appending each letter to word
#print(alphabet[index])<-- REMOVE LATER
answer = [''.join([x[0] for x in codedwords])] #instead of print(codedwords) because that prints[i],[i],[i] not iii
print(answer)
while word.isalpha()==False:#if word is not alphabeticals
print("Invalid Entry!, Please Try again\n")#loop it around again untill it's correct
word=input("Enter the word you want to code\n>>>")
if word.isalpha()==True:#looping round untill correct
for letter in word.lower():
index=alphabet.index(letter)
index=index+offset#Repeated again as above
while index>25:
index=index-26
codedwords.append([alphabet[index]])
answer = [''.join([x[0] for x in codedwords])]
print(answer)
You can use all to check if all letters in user input (word) are alpahanumeric or spaces:
while all(True if letter in alphabet + [' '] else False for letter in word):
>>> all([True, True])
True
>>> all([True, False])
False
>>>
After that:
for letter in word:
if letter == ' ':
codedwords.append([letter])
else:
# Code the letter

Categories

Resources