Counting non-digits in a string

Here's the basic version, using str.isdigit

In [1]:
def count_non_digits(s):
    count = 0
    for i in range(len(s)):
        if not s[i].isdigit():
            count = count + 1
    
    return count
    

A lot of people would be tempted to implement str.isdigit themselves. This is not necessary, but it's good for practicing

In [2]:
def is_str_all_digits(s):
    '''
    (str->bool)
    Return True iff s consists only of digits
    (Note: str.digit is a little bit more complext than that)
    '''
    for i in range(len(s)):
        if s[i] not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']:
            #if s[i] not in "0123456789" is more concise and would work as well
            return False
    return True

Here's a slightly more concise version, which uses a new type of loop construct:

In [3]:
def count_non_digits(s):
    count = 0
    for c in s:
        if not c.isdigit():
            count += 1
    return count

Instead of looping through indices inside s (0, 1, 2, ...., len(s)-1), we can loop through the elements of s directly. This is preferable in situations where all we ever use the i in for i in range() for is to access the element s[i].

Is passwd a valid password?

This is mostly an exercise in finding the right string methods

In [5]:
def password_is_valid(passwd):
    """ (str) -> bool
    A strong password has a length greater than or equal to 6, contains at
    least one lowercase letter, at least one uppercase letter, and at least
    one digit. Return True iff passwd is considered strong.
    >>> check_password(’I<3csc108’)
    True
    """
    
    if len(passwd) < 6:
        return False
    
    #First, set up variables that tell us whether we've encountered 
    #a lowercase letter, and uppercase letter, or a digit
    #Initially, they are all set to False
    has_lowercase = False
    has_uppercase = False
    has_digit = False
    
    for c in passwd:
        if c.isupper():   #Note: blah == (blah == True), so there's no point to going
                          #c.isupper() == True instead
            has_uppercase = True
        elif c.islower():
            has_lowercase = True
        elif c.isdigit():
            has_digit = True
    
    #Now, return True if all three are True
    #(i.e., has_lowercase is True, *and* has_uppercase is True, *and* has_digit is True)
    return has_lowercase and has_uppercase and has_digit

First even number

Here, we just need to keep checking whether the number is even until we encounter an even number, and then return. To check whether a number n is even, we can check whether n % 2 (the remainder of the division of n by 2) is even. If we haven't returned inside the for-loop where we keep checking for evenness, we return -1.

In [6]:
def first_even(items):
    """ (list of int) -> int
    Return the first even number from items. Return -1 if items contains no even numbers.
    >>> first_even([5, 8, 3, 2])
    8
    >>> first_even([7, 1])
    -1
    """
    for n in items:
        if n % 2 == 0:
            return n
    
    return -1

Is the letter a vowel?

Let's try something concise, using str.islower and the in operator

In [7]:
def is_vowel(c):
    return c.lower() in "aeiou"

Disemvowelling

Let's build up the disemvowelled version of a string by first initializing the result to "", and then adding in all the non-vowels

In [8]:
def disemvowel(s):
    #dsmvwl = ""   #too funny of a name... Let's just go wih res
    res = ""
    for c in s:
        if not is_vowel(c):
            res += c   #the same as: res = res + c
            
    return res

Bonus: reversing a string

In [9]:
def reverse_str(s):
    '''return the reversed version of s
    
    reverse_str("abc") -> "cba"
    
    '''
    
    res = ""
    for c in s:
        res = c + res
    return res