Reputation: 15
def valid(s, alphabet):
""" (str, str) -> bool
Return True iff s is composed only of characters in alphabet.
>>> valid('adc', 'abcd')
True
>>> valid('ABC', 'abcd')
False
>>> valid('abc', 'abz')
False
"""
for ch in s:
if ch in alphabet:
return True
else:
return False
I did some error checking and I see that in ch
is only checking until it sees a True value returned.
My code works for the first two but on the third it only checks a
and then returns True and doesn't check the other values.
How can I make the for loop go through each letter and check it with the other string?
Upvotes: 0
Views: 1728
Reputation: 209
The first time a character that is in the alphabet is found, your method returns True. This means the method finishes with the boolean value True as its output. As a result, your for loop does not continue and does not check the remaining characters.
To fix this you can change your code to look like this:
for ch in s:
if ch not in alphabet:
return False
return true
In this way, the method finishes either when a character that is not in the alphabet is found (returning False) or when all the characters have been checked and they are all in the alphabet (returning True).
Upvotes: 0
Reputation: 107297
You just need to tweak the logic by returning False if there is any mismatch character and return True out of the for loop.
for ch in s:
if ch not in alphabet:
return False # 1
return True # 2
The point is that if python executes the #1
it exit the loop so it never meets the #2
until all the characters exist in alphabet
.
Beside this, you have other options which may be more pythonic. On is using set()
object and its proper methods. Another is using built-in functions like all
and any
.
But note that sometimes the cost of converting your string to set
might be greater than the cost of complexity. So you should choose the best way based on your need. You can use timeit
module for measuring the executing time.
Here is a timeit with one of the other answers which used set()
and a generator-based approach with all()
:
In [1]: a = 'abc'
In [2]: b = 'abcd'
In [8]: def regular(s, alphabet):
for ch in s:
if ch not in alphabet:
return False # 1
return True
...:
In [9]: def valid(s, alphabet):
return set(s) < set(alphabet)
...:
In [10]: def generator(s, alphabet):
return all(ch in alphabet for ch in s)
In [11]: %timeit regular(a, b)
1000000 loops, best of 3: 262 ns per loop
In [12]: %timeit valid(a, b)
1000000 loops, best of 3: 635 ns per loop
In [13]: %timeit generator(a, b)
1000000 loops, best of 3: 639 ns per loop
Upvotes: 1
Reputation: 92854
Convert arguments to set
objects and check if one set is a proper subset of other:
def valid(s, alphabet):
return set(s) < set(alphabet)
print(valid('ABC', 'abcd')) # False
print(valid('abc', 'abcd')) # True
set < other
Test whether the set is a proper subset of other, that is, set <= other and set != other.
https://docs.python.org/3/library/stdtypes.html#set
Upvotes: 0
Reputation: 140186
Use set
difference and check that substracting all the letters from the alphabet to the word makes an empty set:
def valid(s, alphabet):
return not set(s) - set(alphabet)
another method using all
, and a set
for better lookup performance:
def valid(s, alphabet):
sa = set(alphabet)
return all(x in sa for x in s) # True if condition True for all chars
Upvotes: 0