Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Python Collections (2016, retired 2019) Lists Disemvowel

Disemvowel - I think I'm close "Getting back letters I wasn't expecting"

Hi! Here is the code I wrote in the code challenge, I feel like I'm close. I made a version of this code in workspace and I got it to work, I pasted that code below. Any tips would be great. I've been working on this for several hours now.

def disemvowel(word):
    vowels = ["a", "e", "i", "o", "u", "A", "E", "I", "O", "U"]
    word_as_list = []
    word_as_list.extend(word)
    try:
        for item in word_as_list:
            if item in vowels:
                word_as_list.remove(item)
            else:
                continue
    except ValueError:
        pass
    word = "".join(word_as_list)
    return word

And here is my fun version of this I built in workspaces, which works:

import os

def clear():
    if os.name == 'nt':
        os.system('cls')
    else:
        os.system('clear')

clear()

vowels = ["a", "e", "i", "o", "u", "A", "E", "I", "O", "U"]

word_as_list = []  

print("""Hi!  Welcome to the disembowel game.
You get to pick a word and I'll remove the vowels.
""")
print("")
word = input("What word would you like me to disemvowel?\n> ")

def disemvowel(word):
    word_as_list.extend(word)
    try:
        for item in word_as_list:
            if item in vowels:
                word_as_list.remove(item)
            else:
                continue
    except ValueError:
        pass

print("Great! Your original word is {}".format(word))

disemvowel(word)

word_new = "".join(word_as_list)
print("")
print("With no vowels, it looks like this: {}".format(word_new))
disemvowel.py
def disemvowel(word):
    vowels = ["a", "e", "i", "o", "u", "A", "E", "I", "O", "U"]
    word_as_list = []
    word_as_list.extend(word)
    try:
        for item in word_as_list:
            if item in vowels:
                word_as_list.remove(item)
            else:
                continue
    except ValueError:
        pass
    word = "".join(word_as_list)
    return word
Jeff Muday
Jeff Muday
Treehouse Moderator 28,720 Points

You're on the right track to solving the problem.

But realize that when you use word_as_list.remove(item), it only removes the FIRST item. So if you had a word like 'Booze' it would only remove the first 'o' and 'e' you would end up with "Boz" which is close, but won't pass the test.

Hint-- rather than a reductive approach you were accomplishing by word_as_list REMOVE, you might want to build the disemvoweled word_as_list from an empty list, and only APPEND non-vowels.

And then your approach of word_as_list JOIN at the end is fine, and you should simply return that value rather than reassigning to "word" variable.

nicole lumpkin
nicole lumpkin
Courses Plus Student 5,328 Points

I agree with Jeff re: building a list versus a reductive approach. Personally, I wouldn't even bother converting word to a list. Instead you could set a variable to an empty string and accumulate any character that's not an upper or lowercase vowel into the empty string using +=. Even though the remove method only removes the first occurrence of an element, since you've written a loop each 'o' in the word 'Booze' will be removed as long as you're not iterating over the same object(list) that you're mutating.

2 Answers

nicole lumpkin
PLUS
nicole lumpkin
Courses Plus Student 5,328 Points

Ah ha!! I found it :) You are mutating the list, word_as_list, while iterating over it! That can cause problems! Read me: https://unspecified.wordpress.com/2009/02/12/thou-shalt-not-modify-a-list-during-iteration/

Instead make a copy of your list for the iteration, and mutate the original. The change occurs on the 6th line of code. :)

def disemvowel(word):
    vowels = ["a", "e", "i", "o", "u", "A", "E", "I", "O", "U"]
    word_as_list = []
    word_as_list.extend(word)
    try:
        for item in word_as_list[:]:
            if item in vowels:
                word_as_list.remove(item)
            else:
                continue
    except ValueError:
        pass
    word = "".join(word_as_list)
    return word

Oh my! Thank you! It makes total sense once you pointed it out. If I'm interating and mutating it's going to get all confused!

Noah Fields
Noah Fields
13,985 Points

So, what I'm about to show you is not the intended way to solve this problem. It's also not something I've seen Treehouse mention Python can do at all, for some reason. However, this ability is so powerful, and so compact, it should be illegal to teach a Python course and ignore it. This is called, list comprehension.

Basically, you take a list, and you sieve through each element of the list based on some requirement. You can do this with the current list, overwriting it; or, you can do it with a new list name, keeping the old one and having the new version around.

For your code, it would look like this:

def disemvowel(word):
vowels = ["a", "e", "i", "o", "u", "A", "E", "I", "O", "U"]
word_as_list = []
word_as_list.extend(word)
try:
    word_as_list = [x for x in word_as_list if x not in vowels]
except ValueError:
    pass
word = "".join(word_as_list)
return word

Let's look at this important bit more closely, shall we?

 word_as_list = [x for x in word_as_list if x not in vowels]

Word_as_list is the list we're checking. You could also do, "new list = (blah blah blah)" or any other name, but as it stands we're overwriting our old list with the new one. x, in this case, is a variable. Name this whatever you want, it doesn't matter. So, x for x in word_as_list means for each element, if the element is not in vowels. This means that, word_as_list is sieved through, keeping every element that is not in vowels - that is, everything that isn't a vowel.

You can do things like, [x for x in numbers if x % 2 == 0], or pretty much anything for any iterable. Cool, huh?

nicole lumpkin
nicole lumpkin
Courses Plus Student 5,328 Points

Yaaaaas Noah! I've come across this in reading more experienced developers code, it's so cool! Thanks for breaking it down. Question, in the expression x for x in word....blah blah, is the first x simply a declaration that x will be the iterative variable? In my experience with loops, you declare the iterative variable within your loop statement once and move on.

res = []
for i in range(5)
    if i %2 == 0:
        res.append(i)

Whereas in a list comprehension you'd write it like this:

res = [i for i in range(5) if i % 2 == 0]
Noah Fields
Noah Fields
13,985 Points

nicole lumpkin

Yes. The first x simply declares that the variable in question will be henceforth referred to as x. Like I mentioned earlier, you can make it be whatever you like and it'll still work the same, but since I have a math background and am learning how to write programs so I can use them to solve math problems, I tend to use more math-focused variable names like x and y in list statements.