Python Forum
Thread Rating:
  • 2 Vote(s) - 2 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Anti Vowel
#1
What is wrong with this code? It should return the text without vowels.

def anti_vowel(text):
  new = list(text)
  for letter in new:
    if letter in "aeiouAEIOU":
        new.remove(letter)
  newest = "".join(new)
  return(newest)

print(anti_vowel("Hey look words"))
Output:
Hy lk Words
instead of:
Output:
Hy lk Wrds
Reply
#2
You're modifying the list you're iterating over, as you iterate over it, which causes some of the items to be skipped over.

When you start iterating over a list, internally an index is created that marks the position of the current item.  Each iteration, that index is incremented.  But if the list has changed, then what you expect to be at that index is no longer what's actually there, which causes issues like this.  To demonstrate, here's your code, with an extra print() function thrown in:
>>> text = "Hey look words"
>>> new = list(text)
>>> for ndx, letter in enumerate(new):
...   print("{} -> {}".format(ndx, letter))
...   if letter.lower() in "aeiou":
...     new.remove(letter)
...
0 -> H
1 -> e
2 ->
3 -> l
4 -> o
5 -> k
6 ->
7 -> w
8 -> o
9 -> d
10 -> s
>>> new
['H', 'y', ' ', 'l', 'k', ' ', 'w', 'o', 'r', 'd', 's']
To get around this... don't modify the list you're iterating over.  Either create a new list, or work with a copy of it.
# so either create a new list...
>>> text = "Hey look words"
>>> new = []
>>> for letter in text:
...   if letter.lower() not in "aeiou":
...     new.append(letter)
...
>>> new
['H', 'y', ' ', 'l', 'k', ' ', 'w', 'r', 'd', 's']

# or work with a copy:
>>> text = "Hey look words"
>>> new = list(text)
>>> for letter in text:
...   if letter.lower() in "aeiou":
...     new.remove(letter)
...
>>> new
['H', 'y', ' ', 'l', 'k', ' ', 'w', 'r', 'd', 's']
If you want to get fancy, you can turn it into a comprehension:
>>> text = "Hey look words"
>>> new = ''.join(letter for letter in text if letter.lower() not in "aeiou")
>>> new
'Hy lk wrds'
That has the benefit of avoiding intermediate lists, and thus saving a little memory (although, for this small case, that is very likely to not be an issue at all).
Reply
#3
def is_not_vowel(char):
    return char.lower() not in 'aeiou'

def vowel_filter(text):
    for char in text:
        if is_not_vowel(char):
            yield char


# with filter built-in
filter_vowels1 = filter(is_not_vowel, 'Hello World')

# with the generator vowel_filter
filter_vowels2 = vowel_filter('Hello World')

# both are lazy evaluated iterables. The
# join mothod of str takes iterables

text_without_vowels1 = ''.join(filter_vowels1)
text_without_vowels2 = ''.join(filter_vowels2)
# or as this fancy generator expressino inside join
text_without_vowels3 = ''.join(char for char in 'Hello World' if is_not_vowel(char))
# the check of the condition happens in the function is_not_vowel
# this makes the code reusable and sometimes easier to understand
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  signal anti-aliasing frohr 0 1,113 May-23-2022, 05:18 PM
Last Post: frohr
  Struggling To Work With Anti-Captcha API digitalmatic7 1 5,682 Oct-09-2017, 09:51 PM
Last Post: nilamo

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020