4

I've tried to be as clear as possible in the title but it was kind of hard to explain it briefly. I have to remove all the vowels from a certain string; to do that, I made a loop that goes through a list composed of the characters of that string, removes the vowels and then joins them:

def anti_vowel(text):
    vow = ["a", "e", "i", "o", "u"]
    chars = []

    for i in text:
        chars.append(i)

    for i in chars:
        if i.lower() in vow:
            chars.remove(i)

    return "".join(chars)

The problem is that when I run the code there will always be a vowel that doesn't get deleted. Examples:

>>> anti_vowel("Hey look Words!")
Hy lk Words!

>>> anti_vowel("Frustration is real")
Frstrton s ral

I'm in no way an expert in Python but this is confusing. Why would it delete some letters and keep others, even if they're exactly the same?

Aleksei Zyrianov
  • 2,294
  • 1
  • 24
  • 32
FanaHOVA
  • 113
  • 1
  • 1
  • 7
  • 3
    See [this](http://arshajii.com/coding-faqs/conc-list-mod.html). – arshajii Apr 19 '14 at 21:54
  • I understand it's not good to loop over a list and remove element from that same list. You could make a copy `copylist = origlist[:]` but there are other ways to do what you want – zlr Apr 19 '14 at 21:55
  • To remove vowels from a string, you can use something like that: `text.translate({ord(v):'' for v in 'aeiouAEIOU'})`. Since you're not asking for a way to that, I'd just leave that here as a comment. – rboy Apr 19 '14 at 22:07

3 Answers3

5

The comment from @arshajii explains why it is not a good idea to remove characters in the loop. To fix the issue in YOUR code, (Note that there are more efficient ways of achieving this, but it looks like you are learning, so I shall leave it here. )

def anti_vowel(text):
    vow = ["a", "e", "i", "o", "u"]
    chars = []

    for i in text: #No need of the two separate loops
        if i.lower() not in vow:
            chars.append(i)

    return "".join(chars)

Demo:

>>> def anti_vowel(text):
...     vow = ["a", "e", "i", "o", "u"]
...     chars = []
...     for i in text: #No need of the two separate loops
...         if i.lower() not in vow:
...             chars.append(i)
...     return "".join(chars)
... 
>>> anti_vowel("Hey look Words!")
'Hy lk Wrds!'
>>> anti_vowel("Frustration is real") 
'Frstrtn s rl'
>>> 
karthikr
  • 97,368
  • 26
  • 197
  • 188
  • Upvote as it answers the question, but using a regex and substring would likely be much more efficient, if slightly more complex. – aruisdante Apr 19 '14 at 22:31
  • @aruisdante Agreed. But as I mentioned, OP seems to be learning python, and just wanted to help correct the code. – karthikr Apr 20 '14 at 00:42
  • Thanks a lot, I found another way to fix the code but I was curious to know how Python decided which letters to keep and which not. Turns out that it was already explained in the question before, my search wasn't thorough enough apparently. – FanaHOVA Apr 22 '14 at 09:49
4

If your goal is to return a string that is equal to the original string with the vowels removed, try:

import re
def anti_vowel(text):
    return re.sub("[aeiou]+", "", text)
mfsiega
  • 2,852
  • 19
  • 22
3

Here's a way that works:

mytext = 'hello world!'
vowels = ['a', 'e', 'i', 'o', 'u']
result = ''
for letter in mytext:
    if letter not in vowels:
        result += letter

print(result)
zlr
  • 789
  • 11
  • 22
  • 2
    This is horrifically inefficient, as python needs to allocate a new string every time you do ``result +=``. You could accomplish wthe same without the need for the plus-equals using a list comprehension as the input to a join, but still better was to do it – aruisdante Apr 19 '14 at 22:29
  • But looping over strings is so cool ! Seriously though, would you then advice against using += whenever possible ? – zlr Apr 20 '14 at 06:54
  • With Strings, yep. There is a PEP somewhere about optimizing python and ``+=`` for strings (as well as ``+``) is one of their low hanging fruit optimizations. Both can be replaced by appropriate use of ``join`` and ``format`` – aruisdante Apr 20 '14 at 12:01