Reputation: 303
I'm trying to debug this program I wrote. How can I tell if, for a given word, hand, and word_list, it returns True or False? I tried initializing a variable failure and then modifying it and printing it's value. It isn't printing, so I don't know if it is behaving like it's supposed to. Any help is appreciated.
I have a function load_words() that returns a list of words. I know word is in word_list (I checked), so just trying to see if word is composed entirely of letters from the keys in the dictionary hand, which in this case it isn't, so it should return False.
Also, what is the difference between .keys() and .iterrkeys(), and is there a better way of looping through hand, perhaps with letter, value in hand.iteritems()?
word = 'axel'
hand2 = {'b':1, 'x':2, 'l':3, 'e':1}
def is_valid_word(word, hand, word_list):
"""
Returns True if word is in the word_list and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or word_list.
word: string
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
failure = False
if word in word_list:
print hand
print [list(i) for i in word.split('\n')][0]
for letter in [list(i) for i in word.split('\n')][0]:
print letter
if letter in hand.keys():
print letter
return True
failure = True
print failure
else:
return False
failure = False
print failure
else:
return False
failure = False
print failure
is_valid_word(word,hand2,load_words())
UPDATE I wish to use this function in my function, but it gives a key error, even though it works fine on its own.
def update_hand(hand, word):
"""
Assumes that 'hand' has all the letters in word.
In other words, this assumes that however many times
a letter appears in 'word', 'hand' has at least as
many of that letter in it.
Updates the hand: uses up the letters in the given word
and returns the new hand, without those letters in it.
Has no side effects: does not modify hand.
word: string
hand: dictionary (string -> int)
returns: dictionary (string -> int)
"""
for letter in [list(i) for i in word.split('\n')][0]:
if letter in hand.keys():
hand[letter] = hand[letter]-1
if hand[letter] <= 0:
del hand[letter]
display_hand(hand)
return hand
Upvotes: 0
Views: 151
Reputation: 2701
The reason why it is not printing out is because you are returning the function before it print
s. This means that the program stops before it reaches the print
statement. For example:
def foo(x):
return x
print x
foo("asdf")
Will return nothing while:
def foo(x):
print x
return x
foo("asdf")
Will print
:
asdf
So, all your statements before return
. If not, it will not execute.
For your second clarification, this post already has your answer https://stackoverflow.com/a/3617008:
In Python 2,
iter(d.keys())
andd.iterkeys()
are not quite equivalent, although they will behave the same. In the first,keys()
will return a copy of the dictionary's list of keys anditer
will then return an iterator object over this list, with the second a copy of the full list of keys is never built.
Note that Python 3 does not have .iterkeys()
too. Python 3 uses the previous .iterkeys()
as the new .keys()
.
Lastly, I will review what is generally wrong with your code and what you want to achieve in descending order of severity.
[list(i) for i in word.split('\n')][0]
is not how you get all the letters from a word.In your for loop, you return True
immediately after the first word is checked. You should return True
after the loop is completed instead.
for letter in word:
if letter not in hand.keys():
return False
return True
Your list comprehension is not needed (I'll tell you why later) and need not be so complex just to get the letters from a word. E.g.
[list(i) for i in word.split('\n')][0]
Actually only does this:
list(word)
In fact, you should just iterate through the word directly (as I did above), it will return the letters one by one:
for letter in word:
# code...
Usually I dislike big chunks of highly indented code. What you can do is make the short code return first. For example:
if word in word_list:
for letter in word:
if letter in hand.keys():
return True
else:
return False
else:
return False
Can be simply be written as:
if word not in word_list:
return False
for letter in word:
if letter in hand.keys():
return True
else:
return False
However, this is just my opinion. Some others may prefer the else
statement so that they know when the code is executed.
Your final code would look like:
def is_valid_word(word, hand, word_list):
if word not in word_list:
return False
for letter in word:
if letter not in hand.keys():
return False
return True
Clean right? However, I assume that you are making something like a scrabble game, so you would count if the words in your hand
can for the word you chose. What you can add is something to count if the number of letters in the word is less than or equal to the number of letters in your hand:
def is_valid_word(word, hand, word_list):
if word not in word_list:
return False
# This makes the word into a "unique list"
letters = set(word)
for letter in letters:
if hand[letter] < word.count(letter):
return False
return True
EDIT
There was a problem with the code. It does not check if the letter
is in hand
in the if statement: if hand[letter] < word.count(letter):
.
def is_valid_word(word, hand, word_list):
if word not in word_list and word not in hand.keys():
return False
letters = set(word)
for letter in letters:
# Add this extra clause
if letter in hand.keys() or hand[letter] < word.count(letter):
return False
return True
Upvotes: 4
Reputation: 2456
You have some indentation issues, and doing something after a return statement is futile.
You don't need to use keys
or iterkeys
the in
operator will check for you, and will work with lists, set, dicts (keys), tuples, strings, ...
The in
operator invokes __contains__
which is supported by most python collections.
Also have look at https://docs.python.org/2/reference/expressions.html#membership-test-details.
He is a minimized example of what you want to do with 3 tests.
def is_valid_word(word, hand, word_list):
"""
Returns True if word is in the word_list and is entirely composed
of letters in the hand. Otherwise, returns False. Does not mutate
hand or word_list.
word: string
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
if word not in word_list:
return False
for letter in word:
if letter not in hand:
return False
return True
print(is_valid_word('bxel',
{'b': 1, 'x': 2, 'l': 3, 'e': 1},
['foo', 'bar', 'bxel']))
print(is_valid_word('axel',
{'b': 1, 'x': 2, 'l': 3, 'e': 1},
['foo', 'bar', 'axel']))
print(is_valid_word('axel',
{'a': 1, 'x': 2, 'l': 3, 'e': 1},
['foo', 'bar', 'axel']))
Upvotes: 0
Reputation: 21082
You can print the result directly print is_valid_word(word,hand2,load_words())
Upvotes: 1