back

python workout: exercise 5

pig latin

problem

Pig Latin (http://mng.bz/YrON) is a common children’s “secret” language in English- speaking countries. (It’s normally secret among children who forget that their parents were once children themselves.) The rules for translating words from English into Pig Latin are quite simple:

  • If the word begins with a vowel (a, e, i, o, or u), add “way” to the end of the word. So “air” becomes “airway” and “eat” becomes “eatway.”

  • If the word begins with any other letter, then we take the first letter, put it on the end of the word, and then add “ay.” Thus, “python” becomes “ythonpay” and “computer” becomes “omputercay.”

(And yes, I recognize that the rules can be made more sophisticated. Let’s keep it sim- ple for the purposes of this exercise.)

For this exercise, write a Python function (pig_latin) that takes a string as input, assumed to be an English word. The function should return the translation of this word into Pig Latin. You may assume that the word contains no capital letters or punctuation.

attempts

This is a straightforward implementation problem – the logic has already been outlined:

def pig_latin(word: str) -> str:
    vowels =  {"a", "e", "i", "o", "u"}
    if word[0] in vowels:
        return word + "way"
    else:
        return word[1:] + word[0] + "ay"
print(pig_latin("air"))
print(pig_latin("computer"))
airway
omputercay

solution

A nice note: Python strings are sequences so our conditional can just be if word[0] in 'aeiou'.

It’s technically not as efficient as a set. But with only 5 items, there’s no practical performance uplift with a set. And it’s cleaner.

The book’s solution:

def pig_latin(word):
    if word[0] in 'aeiou':
        return f'{word}way'
    return f'{word[1:]}{word[0]}ay'
print(pig_latin('python'))
ythonpay

beyond the exercise

handle capitalised words

  • problem

    If a word is capitalized (i.e., the first letter is capital- ized, but the rest of the word isn’t), then the Pig Latin translation should be similarly capitalized.

  • attempts

    We just need to preserve the initial capital letter if present.

    This begs the question: how should we test if the first letter is capitalised?

    A couple approaches spring to mine:

    1. Use the ascii reprensetation of the first character and test whether it’s in the correct interval.
    2. Test whether the first character word[0] is equal to itself but upper (i.e. word[0] == word[0].upper())
    3. Test whether the first character is in the set string.ascii_uppercase.

    There are probably other, cleaner ways. But let’s just use the second approach for now.

    Let’s also take the solution’s implementation as the base to modify:

    def pig_latin(word):
        if word[0] in 'aeiouAEIOU':
            return f'{word}way'
    
        if word[0] == word[0].upper():
            return f'{word[1].upper()}{word[2:]}{word[0].lower()}ay'
        return f'{word[1:]}{word[0].lower()}ay'
    
    print(pig_latin("python"))
    print(pig_latin("air"))
    print(pig_latin("Air"))
    print(pig_latin("Python"))
    
    ythonpay
    airway
    Airway
    Ythonpay
    

handle punctuation

  • problem

    If a word ends with punctuation, then that punctuation should be shifted to the end of the translated word.

  • attempts

    If we assume ending punctuation are single characters only. We can just test if the last character is punctuation or not. And keep it aside until we return the modified word.

    We can use string.punctuation == to perform our test:

    import string
    def pig_latin(word):
        punctuation = ""
        if word[-1] in string.punctuation:
            punctuation = word[-1]
            word = word[:-1]
    
        if word[0] in 'aeiou':
            return f'{word}way{punctuation}'
        return f'{word[1:]}{word[0]}ay{punctuation}'
    
    print(pig_latin('python'))
    print(pig_latin('python.'))
    
    ythonpay
    ythonpay.
    

consider an alternative versio of pig latin

  • problem

    We don’t check to see if the first letter is a vowel, but, rather, we check to see if the word contains two different vowels. If it does, we don’t move the first letter to the end. Because the word “wine” contains two different vowels (“i” and “e”), we’ll add “way” to the end of it, giv- ing us “wineway.” By contrast, the word “wind” contains only one vowel, so we would move the first letter to the end and add “ay,” rendering it “indway.” How would you check for two different vowels in the word?

  • attempts

    The question gives the hint to use sets and even asks the question for us: how can we check a word has 2 different vowels?

    The set hint would suggest iterating through a word and adding each letter to a set of vowels. If the length of the resultant set is greater than 1, we know the input word to contain at least 2 different vowels.

    We should be able to use a comprehension to do this:

    def pig_latin(word):
        word_vowels = {l for l in word if l in 'aeiou'}
        if len(word_vowels) > 1:
            return f'{word}way'
        return f'{word[1:]}{word[0]}ay'
    
    print(pig_latin('wine'))
    print(pig_latin('wind'))
    
    wineway
    indway
    
mail@jonahv.com