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']
Related
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)
I want to check if a word in a generated list is inside a text file
I made an anagram generator, and I want to see if the list created by that generator has a real word by checking if it's inside an English dictionary.
#input
word = input("Word: ")
#function to generate anagrams of the word
def make_anagram(word):
if len(word) <= 1:
yield word
else:
for let in make_anagram(word[1:]):
for i in range(len(word)):
yield let[:i] + word[0:1] + let[i:]
#function to check anagrams
def check_if_anagram(word):
#this is the file with the dictionary
file = open("english-words-master\words.txt")
words = file.read()
#here's where I'm havning trouble
anagram = list(make_anagram(word))
if str(anagram) in words and str(anagram) != word:
print(str(anagram) + " is a real anagram.")
else:
print("there is no real anagram for " + word)
file.close()
the second function always returns the else statement.
I'm still a beginner so I don't understand how lists work very well, what's wrong in the check_if_anagram function?
You are checking if the whole list is in the file. For example, if anagram = ['abc', 'acb'] There you are literally checking:
if "['abc', 'acb']" in words
Which will most likely never happen...
What you want to do, is check each anagram from the list:
anagrams = list(make_anagram(word))
for anagram in anagrams:
if anagram in words and anagram != word:
print(anagram + " is a real anagram.")
break
else:
print("there is no real anagram for " + word)
I'm currently stuck on a problem where I have to find all palingrams in a list. I made one piece of code, however it was not efficient at all and took around 3 and a half hours to finish. I needed to find something that is more time effect.
Right now I am currently stuck with this chunk of code:
import sys
def load(file):
"""Open a text file & turn contents into a list of lowercase strings."""
try:
with open(file) as in_file:
loaded_txt = in_file.read().strip().split('\n')
loaded_txt = [x.lower() for x in loaded_txt]
return loaded_txt
except IOError as e:
print("{}\nError opening {}. Terminating program.".format(e, file),
file=sys.stderr)
sys.exit(1)
def find_palingrams():
pali_list = []
for word in word_list:
if end > 1:
for i in range(end):
if word[i:] == rev_word[:end-i] and rev_word[end-i:] in word_list:
pali_list.append((word, rev_word[end-i:]))
if word[i:] == rev_word[end-i:] and rev_word[:end-i] in word_list:
pali_list.append((rev_word[end-i:], word))
return sorted(pali_list)
I'm having issues with this because it does not print specific outputs that I am looking for. It is printing words, but it is excluding cases such as "aa aa", "a ba", "a baba" etc. There is something that I am not seeing that is causing single letters to not be included fully. I am aware of the end > 1, however even with an attempt to change that I am met with confusion.
Could anyone shed some light?
I guess you mean Palindrome words.
An easier way to check if a word is palindrome:
>>> word = "level"
>>> word == word[::-1]
True
You may wanna use that cleaner way, and then add the word based on the test result:
if word == word[::-1]:
# add it to the list
I'm trying to make a word guessing program and I'm having trouble printing parallel tuples. I need to print the "secret word" with the corresponding hint, but the code that I wrote doesn't work. I can't figure out where I'm going wrong.
Any help would be appreciated :)
This is my code so far:
import random
Words = ("wallet","canine")
Hints = ("Portable money holder","Man's best friend")
vowels = "aeiouy"
secret_word = random.choice(Words)
new_word = ""
for letter in secret_word:
if letter in vowels:
new_word += '_'
else:
new_word += letter
maxIndex = len(Words)
for i in range(1):
random_int = random.randrange(maxIndex)
print(new_word,"\t\t\t",Hints[random_int])
The issue here is that random_int is, as defined, random. As a result you'll randomly get the right result sometimes.
A quick fix is by using the tuple.index method, get the index of the element inside the tuple Words and then use that index on Hints to get the corresponding word, your print statement looking like:
print(new_word,"\t\t\t",Hints[Words.index(secret_word)])
This does the trick but is clunky. Python has a data structure called a dictionary with which you can map one value to another. This could make your life easier in the long run. To create a dictionary from the two tuples we can zip them together:
mapping = dict(zip(Words, Hints))
and create a structure that looks like:
{'canine': "Man's best friend", 'wallet': 'Portable money holder'}
This helps.
Another detail you could fix is in how you create the new_word; instead of looping you can use a comprehension to create the respective letters and then join these on the empty string "" to create the resulting string:
new_word = "".join("_" if letter in vowels else letter for letter in secret_word)
with exactly the same effect. Now, since you also have the dictionary mapping, getting the respective hint is easy, just supply the key new_word to mapping and it'll return the key.
A revised version of your code looks like this:
import random
Words = ("wallet", "canine")
Hints = ("Portable money holder", "Man's best friend")
mapping = dict(zip(Words, Hints))
vowels = "aeiouy"
secret_word = random.choice(Words)
new_word = "".join("_" if letter in vowels else letter for letter in secret_word)
print(new_word,"\t\t\t", d[secret_word])
I am trying to use a Python dictionary object to help translate an input string to other words or phrases. I am having success with translating single words from the input, but I can't seem to figure out how to translate multi-word phrases.
Example:
sentence = input("Please enter a sentence: ")
myDict = {"hello": "hi","mean adult":"grumpy elder", ...ect}
How can I return hi grumpy elder if the user enters hello mean adult for the input?
"fast car" is a key to the dictionary, so you can extract the value if you use the key coming back from it.
If you're taking the input straight from the user and using it to reference the dictionary, get is safer, as it allows you to provide a default value in case the key doesn't exist.
print(myDict.get(sentence, "Phrase not found"))
Since you've clarified your requirements a bit more, the hard part now is the splitting; the get doesn't change. If you can guarantee the order and structure of the sentences (that is, it's always going to be structured such that we have a phrase with 1 word followed by a phrase with 2 words), then split only on the first occurrence of a space character.
split_input = input.split(' ', 1)
print("{} {}".format(myDict.get(split_input[0]), myDict.get(split_input[1])))
More complex split requirements I leave as an exercise for the reader. A hint would be to use the keys of myDict to determine what valid tokens are present in the sentence.
The same way as you normally would.
translation = myDict['fast car']
A solution to your particular problem would be something like the following, where maxlen is the maximum number of words in a single phrase in the dictionary.
translation = []
words = sentence.split(' ')
maxlen = 3
index = 0
while index < len(words):
for i in range(maxlen, 0, -1):
phrase = ' '.join(words[index:index+i])
if phrase in myDict:
translation.append(myDict[phrase])
index += i
break
else:
translation.append(words[index])
index += 1
print ' '.join(translation)
Given the sentence hello this is a nice fast car, it outputs hi this is a sweet quick ride
This will check for each word and also a two word phrase using the word before and after the current word to make the phrase:
myDict = {"hello": "hi",
"fast car": "quick ride"}
sentence = input("Please enter a sentence: ")
words = sentence.split()
for i, word in enumerate(words):
if word in myDict:
print myDict.get(word)
continue
if i:
phrase = ' '.join([words[i-1], word])
if phrase1 in myDict:
print myDict.get(phrase)
continue
if i < len(words)-1:
phrase = ' '.join([word, words[i+1])
if phrase in myDict:
print myDict.get(phrase)
continue