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 defin
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.
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')
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'
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 append
ing, 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])
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.