在Python中使用循环从列表中移除项目

3 投票
5 回答
589 浏览
提问于 2025-04-18 17:23

我刚开始接触编程,主要是学习Python。我正在通过解决各种问题来提高自己的理解能力。

我想定义一个函数,用来从字符串中去掉元音字母。这是我尝试过的代码:

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)

这段代码能去掉字符串开头部分的元音字母,但最后一个单词的元音字母却没有去掉:

比如:

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

有没有人能告诉我哪里出错了,这样我可以从中学习?

谢谢 :)

5 个回答

0

迭代是一个有序的操作。当你在遍历一个列表时删除某个项目,实际上是改变了被删除项目后面所有项目的索引位置。举个例子,当你在处理一个包含元音字母的列表时

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

在第二次循环时,你从列表中删除了字母'e',这时你剩下的列表是

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

然后在第三次循环时,你本来应该检查第三个位置的y,但现在它变成了第三个位置的' '(空格),所以你检查的对象就变了。

mylist.remove(x)

这个操作会在mylist中查找第一个匹配的x并将其删除。当你的循环到达列表中的第一个'o'时,它会把它删除,这样后面的'o'的索引就会减少1。在下一次循环时,它就会查看'k',而不是后面的'o'

那么,为什么你的函数删除了前两个'o'而不是最后一个呢?

你的循环查看了第一个'o',然后是第三个'o'。总的来说,你的循环找到了两个'o'的匹配项,并对它们都执行了remove操作。而且,由于remove函数会找到列表中第一个匹配的项目并将其删除,所以它删除了前两个'o',尽管在删除第二个'o'时,你的循环实际上是在查看第三个'o'

你很幸运在一个包含连续元音的字符串上进行了这个测试。如果你在一个没有连续元音的字符串上进行测试,你的函数可能会删除所有的元音,看起来就像是按你想要的那样工作。

0

你也可以用一种简洁的方式来实现这个,叫做列表推导:

def anti_vowel(text):
    return ''.join(ch for ch in text if ch.upper() not in 'AEIOU')
1

你可以使用列表推导式:

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!

这个列表推导式的作用是从单词中筛选出元音字母。

2

你似乎有点反着来处理这个问题。首先,注意:

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

其实就是:

new = list(text)

其次,为什么不在append之前检查一下呢,而不是之后?这样你只需要遍历一次字符。可以这样做:

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)

这里有个简单的例子:

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

这进一步简化成一个列表推导式

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])
5

在遍历列表时不应该删除列表中的项目。在Stack Overflow上有很多帖子解释了为什么这样做不好。

我会使用filter函数。

>>> 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'

如果把它写成一个函数,应该是这样的:

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

测试

>>> anti_vowel(myString)
'Ths s my strng tht hs vwls n t'

撰写回答