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
Related
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
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})
This question already has answers here:
Count the number of occurrences of a character in a string
(26 answers)
Closed 8 years ago.
I want a string such as 'ddxxx' to be returned as ('d': 2, 'x': 3). So far I've attempted
result = {}
for i in s:
if i in s:
result[i] += 1
else:
result[i] = 1
return result
where s is the string, however I keep getting a KeyError. E.g. if I put s as 'hello' the error returned is:
result[i] += 1
KeyError: 'h'
The problem is with your second condition. if i in s is checking for the character in the string itself and not in the dictionary. It should instead be if i in result.keys() or as Neil mentioned It can just be if i in result
Example:
def fun(s):
result = {}
for i in s:
if i in result:
result[i] += 1
else:
result[i] = 1
return result
print (fun('hello'))
This would print
{'h': 1, 'e': 1, 'l': 2, 'o': 1}
You can solve this easily by using collections.Counter. Counter is a subtype of the standard dict that is made to count things. It will automatically make sure that indexes are created when you try to increment something that hasn’t been in the dictionary before, so you don’t need to check it yourself.
You can also pass any iterable to the constructor to make it automatically count the occurrences of the items in that iterable. Since a string is an iterable of characters, you can just pass your string to it, to count all characters:
>>> import collections
>>> s = 'ddxxx'
>>> result = collections.Counter(s)
>>> result
Counter({'x': 3, 'd': 2})
>>> result['x']
3
>>> result['d']
2
Of course, doing it the manual way is fine too, and your code almost works fine for that. Since you get a KeyError, you are trying to access a key in the dictionary that does not exist. This happens when you happen to come accross a new character that you haven’t counted before. You already tried to handle that with your if i in s check but you are checking the containment in the wrong thing. s is your string, and since you are iterating the character i of the string, i in s will always be true. What you want to check instead is whether i already exists as a key in the dictionary result. Because if it doesn’t you add it as a new key with a count of 1:
if i in result:
result[i] += 1
else:
result[i] = 1
Using collections.Counter is the sensible solution. But if you do want to reinvent the wheel, you can use the dict.get() method, which allows you to supply a default value for missing keys:
s = 'hello'
result = {}
for c in s:
result[c] = result.get(c, 0) + 1
print result
output
{'h': 1, 'e': 1, 'l': 2, 'o': 1}
Here is a simple way of doing this if you don't want to use collections module:
>>> st = 'ddxxx'
>>> {i:st.count(i) for i in set(st)}
{'x': 3, 'd': 2}
I have a dict and a string here, with the dict containing char-count as key value pair. I want to check if the all the characters in the string are completely contained in the dict.
This means that the dict should contain all the chars of the string, with their counts less than or equal to their corresponding values in the dict.
def isValidWord(strng, dct):
"""
Returns True if strng is entirely
composed of letters in the dct.
Otherwise, returns False.
Does not mutate hand or dct.
"""
d={}
for x in strng:
d[x]=d.get(x,0)
for x in d:
if d[x]> dct.get(x,0):
return False
return True
It seems to work well for most cases, but for some cases it doesn't. For example -
isValidWord('chayote', {'a': 1, 'c': 2, 'u': 2, 't': 2, 'y': 1, 'h': 1, 'z': 1,
'o': 2})
This gives output True, however the correct output is False.
This is because there is no e in the dict.
Where is the bug here ? And how can I check if all the pairs in a dict also exist in another dict, possibly with equal or lower corresponding values (of keys).
You meant for the line
d[x]=d.get(x,0)
to be
d[x]=d.get(x,0) + 1
otherwise, all the values in the dictionary would be 0, and the function would always return True (unless the string were empty or any values in the given dictionary were 0.
Also note that it would be easier to use collections.Counter for your first loop:
d = collections.Counter(strng)
As for your question of testing whether one dict is in another, you can do:
all(k in dct and v < dct[k] for k, v in d.items())
This question already has answers here:
Why dict.get(key) instead of dict[key]?
(14 answers)
Closed 4 years ago.
sentence = "The quick brown fox jumped over the lazy dog."
characters = {}
for character in sentence:
characters[character] = characters.get(character, 0) + 1
print(characters)
I don't understand what characters.get(character, 0) + 1 is doing, rest all seems pretty straightforward.
The get method of a dict (like for example characters) works just like indexing the dict, except that, if the key is missing, instead of raising a KeyError it returns the default value (if you call .get with just one argument, the key, the default value is None).
So an equivalent Python function (where calling myget(d, k, v) is just like d.get(k, v) might be:
def myget(d, k, v=None):
try: return d[k]
except KeyError: return v
The sample code in your question is clearly trying to count the number of occurrences of each character: if it already has a count for a given character, get returns it (so it's just incremented by one), else get returns 0 (so the incrementing correctly gives 1 at a character's first occurrence in the string).
To understand what is going on, let's take one letter(repeated more than once) in the sentence string and follow what happens when it goes through the loop.
Remember that we start off with an empty characters dictionary
characters = {}
I will pick the letter 'e'. Let's pass the character 'e' (found in the word The) for the first time through the loop. I will assume it's the first character to go through the loop and I'll substitute the variables with their values:
for 'e' in "The quick brown fox jumped over the lazy dog.":
{}['e'] = {}.get('e', 0) + 1
characters.get('e', 0) tells python to look for the key 'e' in the dictionary. If it's not found it returns 0. Since this is the first time 'e' is passed through the loop, the character 'e' is not found in the dictionary yet, so the get method returns 0. This 0 value is then added to the 1 (present in the characters[character] = characters.get(character,0) + 1 equation).
After completion of the first loop using the 'e' character, we now have an entry in the dictionary like this: {'e': 1}
The dictionary is now:
characters = {'e': 1}
Now, let's pass the second 'e' (found in the word jumped) through the same loop. I'll assume it's the second character to go through the loop and I'll update the variables with their new values:
for 'e' in "The quick brown fox jumped over the lazy dog.":
{'e': 1}['e'] = {'e': 1}.get('e', 0) + 1
Here the get method finds a key entry for 'e' and finds its value which is 1.
We add this to the other 1 in characters.get(character, 0) + 1 and get 2 as result.
When we apply this in the characters[character] = characters.get(character, 0) + 1 equation:
characters['e'] = 2
It should be clear that the last equation assigns a new value 2 to the already present 'e' key.
Therefore the dictionary is now:
characters = {'e': 2}
Start here http://docs.python.org/tutorial/datastructures.html#dictionaries
Then here http://docs.python.org/library/stdtypes.html#mapping-types-dict
Then here http://docs.python.org/library/stdtypes.html#dict.get
characters.get( key, default )
key is a character
default is 0
If the character is in the dictionary, characters, you get the dictionary object.
If not, you get 0.
Syntax:
get(key[, default])
Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
If d is a dictionary, then d.get(k, v) means, give me the value of k in d, unless k isn't there, in which case give me v. It's being used here to get the current count of the character, which should start at 0 if the character hasn't been encountered before.
I see this is a fairly old question, but this looks like one of those times when something's been written without knowledge of a language feature. The collections library exists to fulfill these purposes.
from collections import Counter
letter_counter = Counter()
for letter in 'The quick brown fox jumps over the lazy dog':
letter_counter[letter] += 1
>>> letter_counter
Counter({' ': 8, 'o': 4, 'e': 3, 'h': 2, 'r': 2, 'u': 2, 'T': 1, 'a': 1, 'c': 1, 'b': 1, 'd': 1, 'g': 1, 'f': 1, 'i': 1, 'k': 1, 'j': 1, 'm': 1, 'l': 1, 'n': 1, 'q': 1, 'p': 1, 's': 1, 't': 1, 'w': 1, 'v': 1, 'y': 1, 'x': 1, 'z': 1})
In this example the spaces are being counted, obviously, but whether or not you want those filtered is up to you.
As for the dict.get(a_key, default_value), there have been several answers to this particular question -- this method returns the value of the key, or the default_value you supply. The first argument is the key you're looking for, the second argument is the default for when that key is not present.