在Python中使用循环从列表中移除项目
我刚开始接触编程,主要是学习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 个回答
迭代是一个有序的操作。当你在遍历一个列表时删除某个项目,实际上是改变了被删除项目后面所有项目的索引位置。举个例子,当你在处理一个包含元音字母的列表时
['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'
。
你很幸运在一个包含连续元音的字符串上进行了这个测试。如果你在一个没有连续元音的字符串上进行测试,你的函数可能会删除所有的元音,看起来就像是按你想要的那样工作。
你也可以用一种简洁的方式来实现这个,叫做列表推导:
def anti_vowel(text):
return ''.join(ch for ch in text if ch.upper() not in 'AEIOU')
你可以使用列表推导式:
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!
这个列表推导式的作用是从单词中筛选出元音字母。
你似乎有点反着来处理这个问题。首先,注意:
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])
你在遍历列表时不应该删除列表中的项目。在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'