Python where am I wrong to have a function remove vowels in a string?

I am following codecademy's tutorial, question: "Define a function called anti_vowel that takes one line, text, as input, and returns text with all vowels removed.

For example: anti_vowel ("Hey you!") Should return "Hy Y!"

Code:

def anti_vowel(text):
    textlist = list(text)
    print textlist
    for k in textlist:
        if k in"aeiouAEIOU":
            print k
            textlist.remove(k)
    return "".join(textlist)

      

Error: "Oops, try again. Your function will crash on anti_vowel (" Hey look words! "). It returns" Words related to Hy lk! "when he should return" Hy lk Wrds! ".

I don't know why else 'there'? Can someone tell me the reason for the error? Thanks!

+3


source to share


3 answers


The reason is already explained in the comments by @jonrsharpe.

I would like to show you an optimized version that works and uses a list comprehension:

def anti_vowel(text):
    return "".join([x for x in text if x not in "aeiouAEIOU"])

print anti_vowel("Hey look Words!")

      



output:

Hy lk Wrds!

      

+8


source


Python uses an index when traversing lists. Changing the list is, as mentioned, a bad idea because the documentation says not to do it and does not specify behavior. Here's what's going on

Hey look Words!
^
Hey look Words!
 ^ found 'e' so we remove it
Hy look Words!
  ^ note that we stepped one step but the removal made us skip 'y'
...
Hy look Words!
    ^ found 'o' so we remove it
Hy lok Words
     ^ again we stepped one step, but the removal made us skip 'o'
...
Hy lok Words!
        ^ found 'o' so we remove the first o
Hy lk Words!
         ^ again we stepped one step, but removing a letter before the cursor make us skip 'r'.
...
Hy lk Words!
           ^ consider youself lucky python happens to check the actual length of the list at each iteration - or the cursor would continue into the wilderness.

      



The lesson learned is that you don't modify the container while you are iterating, unless the documentation explicitly says you can do it (sometimes it is allowed under certain restrictions).

+3


source


You shouldn't modify the list while iterating over it, because you are changing the length and not iterating as you expect, you can instead use yield

a generator to return without vowels and then concatenate it:

def anti_vowel(text):
    for k in textlist:
        if k not in"aeiouAEIOU":
              yield k

      

Demo:

print ''.join(anti_vowel("Hey look Words!"))
Hy lk Wrds!

      

Please note that in this case, you do not need to convert the string to a list.

Also, as a more elegant way, you can do it with re.sub

:

import re
def anti_vowel(text):
  return re.sub(r'[aeiou]+','',text,flags=re.I)

      

+2


source







All Articles