3

I am very new to programming in general and have started with Python. I am working through various problems to try and better my understanding.

I am trying to define a function that removes vowels from a string. This is what I have tried:

def anti_vowel(text):
    new = []
    for i in range(len(text)):
        new.append(text[i])
    print new
    for x in new:
        if x == "e" or x == "E" or x == "a" or x == "A" or x == "i" or x == "I" or x == "o" or x == "O" or x == "u" or x == "U":
            new.remove(x)
    return "".join(new)

This is removing vowels from the first words of a string, but not the final word:

eg:

anti_vowel("Hey look words!")    
returns: "Hy lk words!"

Can somebody please explain where I am going wrong so I can learn from this?

Thanks :)

j-i-l
  • 10,281
  • 3
  • 53
  • 70
  • 2
    Why don't you just *not `append` it* if you don't want it, rather than adding them all then removing some? – jonrsharpe Aug 15 '14 at 12:32

5 Answers5

5

You should not delete items from a list while iterating through it. You will find numerous posts on Stack Overflow explaining why.

I would use the filter function

>>> vowels = 'aeiouAEIOU'
>>> myString = 'This is my string that has vowels in it'
>>> filter(lambda i : i not in vowels, myString)
'Ths s my strng tht hs vwls n t'

Written as a function, this would be

def anti_vowel(text):
    vowels = 'aeiouAEIOU'
    return filter(lambda letter : letter not in vowels, text)

Test

>>> anti_vowel(myString)
'Ths s my strng tht hs vwls n t'
Community
  • 1
  • 1
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
2

You seem to have approached this a bit backwards. Firstly, note that:

new = []
for i in range(len(text)):
    new.append(text[i])

is just:

new = list(text)

Secondly, why not check before appending, rather than afterwards? Then you only have to iterate over the characters once. This could be:

def anti_vowel(text):
    """Remove all vowels from the supplied text.""" # explanatory docstring
    non_vowels = [] # clear variable names
    vowels = set("aeiouAEIOU") # sets allow fast membership tests
    for char in text: # iterate directly over characters, no need for 'i'
        if char not in vowels: # test membership of vowels
            non_vowels.append(char) # add non-vowels only
    return "".join(non_vowels)

A quick example:

>>> anti_vowel("Hey look words!")
'Hy lk wrds!'

This simplifies further to a list comprehension:

def anti_vowel(text):
    """Remove all vowels from the supplied text."""
    vowels = set("aeiouAEIOU")
    return "".join([char for char in text if char not in vowels])
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
1

You can use a list comp:

def anti_vowel(text):
    vowels = 'aeiouAEIOU'
    return "".join([x for x in text if x not in vowels])
print anti_vowel("Hey look words!")
Hy lk wrds!

The list comprehension filters the vowels from the words.

Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
0

You can also do it succinctly with a comprehension:

def anti_vowel(text):
    return ''.join(ch for ch in text if ch.upper() not in 'AEIOU')
khelwood
  • 55,782
  • 14
  • 81
  • 108
0

Iteration is an indexed operation. When you remove an item from a list while iterating over it, you essentially change the indices of every item in the list that follows the item you removed. When you loop over the list

['h','e','y',' ','l','o','o','k',' ','w','o','r','d','s']

whilst removing an item in 'aeiou', on the second iteration of the loop, you remove 'e' from your list and your left with

['h','y',' ','l','o','o','k',' ','w','o','r','d','s']

then on the third iteration, instead of testing your if statement on the y, which was originally in the third position, it is now testing it on the ' ', which is what is in the third position of the the modified list.

mylist.remove(x)

will search for the first matching value of x inmylist and remove it. When your loop gets to the first 'o' in the list, it removes it, thereby changing the index of the following 'o' by -1. On the next iteration of the loop, it is looking at 'k' instead of the subsequent 'o'.

However, why then did your function remove the first two 'o's and not the last one?

Your loop looked at the first 'o', not the second 'o', and looked at the third 'o'. In total your loop found two matches for 'o' and performed the remove function on both. And again, since the remove function will find the first matching item in the list and remove it, that's why it removed the first two 'o's, although for the removal of the second 'o' your loop was actually iterating over the third 'o'.

You were fortunate to have done this test on a string with consecutive vowels. Had you done it on a string without consecutive vowels, you would have removed all the vowels with your function and it would have appeared to work as you intended.

ionalchemist
  • 398
  • 2
  • 17