Python key error in function - python

I have a function that should return the number of words that contain each vowel (all lowercase), but I keep getting a key error. I'd appreciate any help in figuring it out. Thank you.
def vowelUseDict(t):
'''computes and returns a dictionary with the number of words in t containing each vowel
'''
vowelsUsed = {}
strList = t.split()
newList = []
vowels ='aeiou'
for v in vowels:
for strs in strList:
if v in strs and strs not in newList:
newList.append(strs)
vowelsUsed[v] = 1
if v in strs and strs in newList:
vowelsUsed[v] += 1
return vowelsUsed
text = 'like a vision she dances across the porch as the radio plays'
print(vowelUseDict(text))
#{'e': 5, 'u': 0, 'o': 4, 'a': 6, 'i': 3}

from collections import Counter
def vowelUseDict(t):
vowels = 'aeiou'
cnt = sum(map(Counter, t.split()), Counter())
return {k: cnt[k] if k in cnt else 0 for k in vowels}

That's because newList keeps the words from the previous vowels. Once you reach "like" for "i", it already exists since it was added for "e". This means that it tries to add to the value for key "i" in vowelsUsed, which doesn't exist (it would get added the first time a word is found that hasn't been added for another vowel).
Since (judging by the last line) you want every vowel to be in the resulting dict, you can just create the dict with all the vowels as keys and the values as zero, and you don't even have to check if a key exists. Just increase the value by one if the word contains the vowel.
The resulting code would be something like this:
def vowelUseDict(t):
'''computes and returns a dictionary with the number of words in t containing each vowel
'''
strList = t.split()
vowels ='aeiou'
vowelsUsed = {v: 0 for v in vowels}
for v in vowels:
for strs in strList:
if v in strs:
vowelsUsed[v] += 1
return vowelsUsed
text = 'like a vision she dances across the porch as the radio plays'
print(vowelUseDict(text))
#{'e': 5, 'u': 0, 'o': 4, 'a': 6, 'i': 3}
Roy Orbison singing for the lonely; hey, that's me and I want you only

Related

Filtering a dictionary to a certain condition but it does not produce required results

I would like my code to print all occurrences of words that appear once. I have produced this code below, however, the result only shows the first instance of the word occurring once but not all of them. I am not sure where the problem is and how to fix it. Any help would be greatly appreciated.
import re
from collections import Counter
def inspiration(text):
quote = re.findall(r'\w+', text.lower())
quote_dict = dict(Counter(quote).most_common())
quote_one = {}
for key, value in quote_dict.items():
if value == 1:
quote_one[key]= value
return quote_one
print(inspiration("We know what we are, but know not what we may be- William Shakespeare"))
Expected output: {"are":1, "but":1, "not":1, "be":1, "William":1, "Shakespeare":1}
Try this :
import re
from collections import Counter
def inspiration(text):
lst = re.findall(r'\w+', text.lower())
return {k: v for k, v in Counter(lst).items() if v == 1}
print(inspiration("We know what we are, but know not what we may be- William Shakespeare"))
output :
{'are': 1, 'but': 1, 'not': 1, 'may': 1, 'be': 1, 'william': 1, 'shakespeare': 1}
Note :
1- There is no need for .most_common()
2- Counter is inherited from dict, so it has .items() , No need to convert it to a dictionary.
Your return is in the for block so it returns at the end of the first iteration, what you need is returning after iterating on all pairs. Also you don't need the value as it's always 1 just return a list of words
def inspiration(text):
quote = re.findall(r'\w+', text.lower())
quote_dict = dict(Counter(quote).most_common())
quote_one = []
for key, value in quote_dict.items():
if value == 1:
quote_one.append(key)
return quote_one
Improvements
don't need to use most_common, you don't need an ordered iteration
so don't need back wrapping to dict, you could keep the list of pairs
Combined with a dict-comprehension :
def inspiration(text):
return [k for k, v in Counter(re.findall(r'\w+', text.lower())).items() if v == 1]
quote_one[key]= value should he indented to the right because it comes under if statement.
return ends the function. So it will end the function after the first iteration.
Here is the correct code
def inspiration(text):
quote = re.findall(r'\w+', text.lower())
quote_dict = dict(Counter(quote).most_common())
quote_one = {}
for key, value in quote_dict.items():
if value == 1:
quote_one[key]= value
return quote_one

How would I detect insertion of the same key with a different value into a dict?

So my goal for this problem is to, given 2 strings, str1 and str2, create a dictionary such that the characters in str1 are the keys and the corresponding characters in str2 are the values.
ie. crackthecode('apple','byytr') returns
{'a':'b','p':'y','l':'t','e':'r'}
and if it is inconsistent, ie. crackthecode('apple','byptr') then returns
{}, an empty dictionary.
This is my code, I'm just not sure how to do the inconsistent case.
PS. I cannot use zip for this question.
Below is my code.
def crackthecode(str1, str2):
final = {}
x = 0
for i in list(str1):
final[i]=str2[x]
x = x + 1
return final
All help is appreciated, thanks!
You can check if the key is already present in the dictionary, and compare the value with the new character. If they are not equal, return an empty dictionary. Otherwise, add the key-value pair to the dictionary.
You can use this code which uses the EAFP principle.
>>> def crackthecode(str1, str2):
final = {}
for i, key in enumerate(str1):
try:
if final[key] != str2[i]:
return {}
except KeyError:
final[key] = str2[i]
return final
>>> crackthecode('apple','byytr')
{'a': 'b', 'p': 'y', 'l': 't', 'e': 'r'}
>>> crackthecode('apple','byptr')
{}
Edit: Same code without using enumerate (requested by OP)
def crackthecode(str1, str2):
final = {}
for i in range(len(str1)):
try:
if final[str1[i]] != str2[i]:
return {}
except KeyError:
final[str1[i]] = str2[i]
return final

Printing list of words from dictionary

(Sorry for the long question)
print_most_common() function which is passed two parameters, a dictionary containing words and their corresponding frequencies e.g.
{"fish":9, "parrot":8, "frog":9, "cat":9, "stork":1, "dog":4, "bat":9, "rat":3}
and, an integer, the required number of characters. The function gets a list of all the words of the required number of characters which are keys of the dictionary and have the highest frequency for words of that length. The function first prints the string made up of the word length (the second parameter), followed by " letter keywords: ", then prints a list of all the words of the required length (keys from the dictionary) which have the highest frequency followed by the frequency value. The list of words must be sorted alphabetically.
e.g.
word_frequencies = {"fish":9, "parrot":8, "frog":9, "cat":9,
"stork":1, "dog":4, "bat":9, "rat":3}
print_most_common(word_frequencies, 3)
print_most_common(word_frequencies, 4)
print_most_common(word_frequencies, 5)
Will print:
3 letter keywords: ['bat', 'cat'] 9
4 letter keywords: ['fish', 'frog'] 9
5 letter keywords: ['stork'] 1
How would I define the print_most_common(words_dict, word_len) function?
how about this.
freq_dict = {k: v for k, v in word_frequencies.items() if len(k) == word_len}
for example:
>> freq_dict = {k: v for k, v in word_frequencies.items() if len(k) == 3}
>> print(freq_dict)
>> {'bat': 9, 'cat': 9, 'dog': 4, 'rat': 3}
This should work for a Python 2 implementation at least, updating to 3 should not be difficult.
Asav provides a way to get dictionary with a words of word_len and their corresponding frequency. You can then retrieve the max value from the frequencies and consequently retrieve the list of words with that frequency.
def print_most_common(words_dict, word_len):
wl_dict = {k: v for k, v in words_dict.items() if len(k) == word_len}
max_value = wl_dict[max(wl_dict, key=wl_dict.get)]
res_list = [key for key,val in wl_dict.items() if val == max_value]
print '%d letter keywords %s %d' % (word_len, res_list, max_value)
Do let me know if you want further decomposition or explanation.
Here is a possible solution:
Get all words of the required length.
filtered_words = {k: v for k, v in words_dict.items() if len(k) == word_len}
Get the maximum count for that length.
max_count = max(filtered_words.values())
Filter the words with that count.
[k for k, v in filtered_words.items() if v == max_count]
Full Code
def print_most_common(words_dict, word_len):
filtered_words = {k: v for k, v in words_dict.items() if len(k) == word_len}
max_count = max(filtered_words.values())
print word_len, 'letter keywords:', [k for k, v in filtered_words.items() if v == max_count], max_count

Key error in dictionary. How to make Python print my dictionary?

In my homework, this question is asking me to make a function where Python should create dictionary of how many words that start with a certain letter in the long string is symmetrical. Symmetrical means the word starts with one letter and ends in the same letter. I do not need help with the algorithm for this. I definitely know I have it right, but however I just need to fix this Key error that I cannot figure out. I wrote d[word[0]] += 1, which is to add 1 to the frequency of words that start with that particular letter.
The output should look like this (using the string I provided below):
{'d': 1, 'i': 3, 't': 1}
t = '''The sun did not shine
it was too wet to play
so we sat in the house
all that cold cold wet day
I sat there with Sally
we sat there we two
and I said how I wish
we had something to do'''
def symmetry(text):
from collections import defaultdict
d = {}
wordList = text.split()
for word in wordList:
if word[0] == word[-1]:
d[word[0]] += 1
print(d)
print(symmetry(t))
You're trying to increase the value of an entry which has yet to be made resulting in the KeyError. You could use get() for when there is no entry for a key yet; a default of 0 will be made (or any other value you choose). With this method, you would not need defaultdict (although very useful in certain cases).
def symmetry(text):
d = {}
wordList = text.split()
for word in wordList:
key = word[0]
if key == word[-1]:
d[key] = d.get(key, 0) + 1
print(d)
print(symmetry(t))
Sample Output
{'I': 3, 'd': 1, 't': 1}
You never actually use collections.defaultdict, although you import it. Initialize d as defaultdict(int), instead of as {}, and you're good to go.
def symmetry(text):
from collections import defaultdict
d = defaultdict(int)
wordList = text.split()
for word in wordList:
if word[0] == word[-1]:
d[word[0]] += 1
print(d)
print(symmetry(t))
Results in:
defaultdict(<class 'int'>, {'I': 3, 't': 1, 'd': 1})

python comparing dictionaries

level: beginner
word= 'even'
dict2 = {'i': 1, 'n': 1, 'e': 1, 'l': 2, 'v': 2}
i want to know if word is entirely composed of letters in dict2
my approach:
step 1 : convert word to dictionary(dict1)
step2:
for k in dict1.keys():
if k in dict2:
if dict1[k] != dict2[k]:
return False
return True
by adding a print statement i can see that this simply ends too early
e.g. as soon as the first IF condition is met the loop exits and i won't get a correct answer. i think this is easy but google and python doc didn't return any good
hints so i'm trying here.
Thanks Baba
UPDATE
the number of times that each letter ocurs in the word needs to be smaller or equal to the number of times it apears in dict2. That way i am guaranteed that word is entirely made up of elements of dict2.
for k in word.keys(): # word has ben converted to key already
if k not in hand:
return False
elif k in hand:
if word[k] > hand[k]:
return False
return True
>>> word= 'even'
>>> dict2 = {'i': 1, 'n': 1, 'e': 1, 'l': 2, 'v': 2}
>>> set(word).issubset(set(dict2.keys()))
True
Unless you need it for something else, don't bother constructing dict1. Just do this:
for c in word:
if c not in dict2:
return False
return True
Of course, you could also use a set instead of a dict to hold the letters.
You only want to return true after all the checks, so stick it after the loop. Here it is as a straight modification of your code:
for k in dict1.keys():
if k in dict2:
if dict1[k] != dict2[k]:
return False
return True
in your code, just move the "return True" to be outside all the loops. That is, only return true if your loops complete without finding a non-matching value. Whether that's truly what you want for your actual code is hard to say, but moving the "return True" fixes the logic error in the code you posted.
>>> word = {'e':2, 'v':1, 'n':1}
>>> hand= {'i': 1, 'n': 1, 'e': 1, 'l': 2, 'v': 2}
>>> all(k in hand and v <= hand[k] for k,v in word.items())
False
and now see the true case
>>> hand['e']+=1
>>> all(k in hand and v <= hand[k] for k,v in word.items())
True

Categories