Enes Dal
Enes Dal

Reputation: 15

Boolean comparing two strings

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

Answers (4)

Theo Vasileiadis
Theo Vasileiadis

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

Kasravnd
Kasravnd

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

RomanPerekhrest
RomanPerekhrest

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

Jean-Fran&#231;ois Fabre
Jean-Fran&#231;ois Fabre

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

Related Questions