循环“忘记”以删除一些项目[重复]

2024-11-28 08:37:00
admin
原创
9
摘要:问题描述:在此代码中,我尝试创建一个函数 anti_vowel,该函数将从字符串中删除所有元音 (aeiouAEIOU)。我认为它应该可以正常工作,但是当我运行它时,示例文本“Hey look Words!”被返回为“Hy lk Words!”。它“忘记”删除最后一个“o”。怎么会这样?text = &quo...

问题描述:

在此代码中,我尝试创建一个函数 anti_vowel,该函数将从字符串中删除所有元音 (aeiouAEIOU)。我认为它应该可以正常工作,但是当我运行它时,示例文本“Hey look Words!”被返回为“Hy lk Words!”。它“忘记”删除最后一个“o”。怎么会这样?

text = "Hey look Words!"

def anti_vowel(text):

    textlist = list(text)

    for char in textlist:
        if char.lower() in 'aeiou':
            textlist.remove(char)

    return "".join(textlist)

print anti_vowel(text)

解决方案 1:

您正在修改迭代的列表,这必然会导致一些不直观的行为。相反,请复制列表,这样您就不会从迭代的内容中删除元素。

for char in textlist[:]: #shallow copy of the list
    # etc

为了澄清您看到的行为,请查看此内容。将print char, textlist其放在 (原始) 循环的开头。您可能希望这会在列表旁边垂直打印出您的字符串,但您实际上会得到以下内容:

H ['H', 'e', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
e ['H', 'e', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
  ['H', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!'] # !
l ['H', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
o ['H', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
k ['H', 'y', ' ', 'l', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!'] # Problem!!
  ['H', 'y', ' ', 'l', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
W ['H', 'y', ' ', 'l', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
o ['H', 'y', ' ', 'l', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!'] 
d ['H', 'y', ' ', 'l', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
s ['H', 'y', ' ', 'l', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
! ['H', 'y', ' ', 'l', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
Hy lk Words!

那么到底发生了什么?for x in yPython 中的 nice 循环实际上只是语法糖:它仍然通过索引访问列表元素。因此,当您在迭代列表中删除元素时,您会开始跳过值(如上所示)。结果,您永远不会看到o中的第二个"look";您跳过它是因为当您删除前一个元素时索引已经“超过”了它。然后,当您到达 中时o"Words"您将删除 的第一个出现'o',即您之前跳过的那个。


正如其他人提到的,列表推导式可能是一种更好(更干净、更清晰)的方法。利用 Python 字符串可迭代的事实:

def remove_vowels(text): # function names should start with verbs! :)
    return ''.join(ch for ch in text if ch.lower() not in 'aeiou')

解决方案 2:

其他答案会告诉您为什么for在更改列表时会跳过项目。此答案会告诉您如何在不使用显式循环的情况下删除字符串中的字符。

使用str.translate()

vowels = 'aeiou'
vowels += vowels.upper()
text.translate(None, vowels)

这将删除第二个参数中列出的所有字符。

演示:

>>> text = "Hey look Words!"
>>> vowels = 'aeiou'
>>> vowels += vowels.upper()
>>> text.translate(None, vowels)
'Hy lk Wrds!'
>>> text = 'The Quick Brown Fox Jumps Over The Lazy Fox'
>>> text.translate(None, vowels)
'Th Qck Brwn Fx Jmps vr Th Lzy Fx'

在 Python 3 中,该str.translate()方法(Python 2 unicode.translate():)的不同之处在于它不接受deletechars参数;第一个参数是一个将 Unicode 序数(整数值)映射到新值的字典。用于None需要删除的任何字符:

# Python 3 code
vowels = 'aeiou'
vowels += vowels.upper()
vowels_table = dict.fromkeys(map(ord, vowels))
text.translate(vowels_table)

您还可以使用str.maketrans()静态方法来生成该映射:

vowels = 'aeiou'
vowels += vowels.upper()
text.translate(text.maketrans('', '', vowels))

解决方案 3:

引用文档:

注意:当循环修改序列时,有一个微妙之处(这只能发生在可变序列,即列表上)。内部计数器用于跟踪下一个要使用的项目,并且每次迭代时都会递增。当此计数器达到序列的长度时,循环终止。这意味着,如果套件从序列中删除当前(或前一个)项目,则将跳过下一个项目(因为它获取了已经处理过的当前项目的索引)。同样,如果套件在当前项目之前在序列中插入一个项目,则下次循环时将再次处理当前项目。这可能会导致严重的错误,可以通过使用整个序列的切片制作临时副本来避免,例如,

for x in a[:]:
    if x < 0: a.remove(x)

使用 迭代列表的浅表副本[:]。您在迭代列表时修改列表,这会导致遗漏一些字母。

循环for跟踪索引,因此当您删除索引处的项目时i,第 位置处的下一个项目i+1将移动到当前索引(i),因此在下一次迭代中您实际上会选择i+2第 一个项目。

让我们举一个简单的例子:

>>> text = "whoops"
>>> textlist = list(text)
>>> textlist
['w', 'h', 'o', 'o', 'p', 's']
for char in textlist:
    if char.lower() in 'aeiou':
        textlist.remove(char)

迭代 1:索引 = 0。

char = 'W'因为它位于索引 0 处。由于它不满足该条件,因此您需要注意。

迭代 2:索引 = 1。

char = 'h'因为它位于索引 1。这里没有什么可做的了。

迭代 3:索引 = 2。

char = 'o'因为它位于索引 2 处。由于此项满足条件,所以它将从列表中删除,并且其右侧的所有项将向左移动一位以填补空白。

现在textlist变成:

   0    1    2    3    4
`['w', 'h', 'o', 'p', 's']`

如您所见,另一个'o'已移至索引 2,即当前索引,因此它将在下一次迭代中被跳过。因此,这就是某些项目在您的迭代中被跳过的原因。每当您删除一个项目时,下一个项目都会从迭代中跳过。

迭代 4:索引 = 3。

char = 'p'就像索引 3 那样。

....


使固定:

遍历列表的浅拷贝来修复此问题:

for char in textlist[:]:        #note the [:]
    if char.lower() in 'aeiou':
        textlist.remove(char)

其他选择:

列表理解:

str.join使用和的一行代码list comprehension

vowels = 'aeiou'
text = "Hey look Words!"
return "".join([char for char in text if char.lower() not in vowels])

正则表达式:

>>> import re
>>> text = "Hey look Words!"
>>> re.sub('[aeiou]', '', text, flags=re.I)
'Hy lk Wrds!'

解决方案 4:

您正在修改迭代的数据。不要这样做。

''.join(x for x in textlist in x not in VOWELS)

解决方案 5:

text = "Hey look Words!"

print filter(lambda x: x not in "AaEeIiOoUu", text)

输出

Hy lk Wrds!

解决方案 6:

您正在迭代一个列表并同时从中删除元素。

首先,我需要确保你清楚地理解了char在 中的作用for char in textlist: ...。以我们到达字母 'l' 的情况为例。情况不是这样的:

['H', 'e', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
                      ^
                    char

char和列表中字母 'l' 的位置之间没有任何联系。如果你修改char,列表不会被修改。情况更像是这样的:

['H', 'e', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
                      ^
char = 'l'

请注意,我保留了^符号。这是管理循环的代码for char in textlist: ...用来跟踪其在循环中的位置的隐藏指针。每次进入循环体时,指针都会前进,并且指针引用的字母会复制到中char

当你有两个连续的元音时,就会出现问题。我会向你展示从到达“l”的那一刻开始会发生什么。请注意,我还将单词“look”改为“leap”,以更清楚地说明发生了什么:

前进指针到下一个字符 ('l') 并复制到char

['H', 'e', 'y', ' ', 'l', 'e', 'a', 'p', ' ', 'W', 'o', 'r', 'd', 's', '!']
                   -> ^
char = 'l'

char('l') 不是元音,因此不执行任何操作

前进指针到下一个字符 ('e') 并复制到char

['H', 'e', 'y', ' ', 'l', 'e', 'a', 'p', ' ', 'W', 'o', 'r', 'd', 's', '!']
                        -> ^
char = 'e'

char('e') 是元音,因此删除第一次出现的char('e')

['H', 'e', 'y', ' ', 'l', 'e', 'a', 'p', ' ', 'W', 'o', 'r', 'd', 's', '!']
                           ^

['H', 'e', 'y', ' ', 'l',      'a', 'p', ' ', 'W', 'o', 'r', 'd', 's', '!']
                           ^

['H', 'e', 'y', ' ', 'l',   <- 'a', 'p', ' ', 'W', 'o', 'r', 'd', 's', '!']
                           ^

['H', 'e', 'y', ' ', 'l', 'a', 'p', ' ', 'W', 'o', 'r', 'd', 's', '!']
                           ^

前进指针到下一个字符 ('p') 并复制到char

['H', 'e', 'y', ' ', 'l', 'a', 'p', ' ', 'W', 'o', 'r', 'd', 's', '!']
                             -> ^
char = 'p'

当你删除“e”时,“e”后面的所有字符都会向左移动一个位置,所以就像remove指针前进了一样。结果是你跳过了“a”。

一般来说,你应该避免在迭代列表时修改列表。最好从头开始构建一个新列表,而 Python 的列表推导式是执行此操作的完美工具。例如

print ''.join([char for char in "Hey look Words" if char.lower() not in "aeiou"])

但是如果你还没有了解理解的话,最好的方法可能是:

text = "Hey look Words!"

def anti_vowel(text):

  textlist = list(text)
  new_textlist = []

  for char in textlist:
    if char.lower() not in 'aeiou':
      new_textlist.append(char)

    return "".join(new_textlist)

print anti_vowel(text)

解决方案 7:

列表推导:

vowels = 'aeiou'
text = 'Hey look Words!'
result = [char for char in text if char not in vowels]
print ''.join(result)

解决方案 8:

其他人已经用你的代码解释了这个问题。对于你的任务,生成器表达式更简单,也不容易出错。

>>> text = "Hey look Words!"
>>> ''.join(c for c in text if c.lower() not in 'aeiou')
'Hy lk Wrds!'

或者

>>> ''.join(c for c in text if c not in 'AaEeIiOoUu')
'Hy lk Wrds!'

但这str.translate是最好的方法。

解决方案 9:

您不应该从迭代列表中删除项目:但您可以使用列表理解语法从旧列表创建新列表。列表理解在这种情况下非常有用。您可以在此处阅读有关列表理解的内容

因此你的解决方案将是这样的:

text = "Hey look Words!"

def anti_vowel(text):
    return "".join([char for char in list(text) if char.lower() not in 'aeiou'])

print anti_vowel(text)

很漂亮不是吗 :P

解决方案 10:

尽量不要对字符串使用 list() 函数。这会使事情变得更加复杂。

与 Java 不同,在 Python 中,字符串被视为数组。然后,尝试使用索引进行循环和 del 关键字。

for x in range(len(string)):
    if string[x].lower() in "aeiou":
        del string[x]
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   649  
  如何借鉴华为IPD体系优化企业研发?在当今竞争激烈的市场环境中,企业要想保持技术领先和产品竞争力,必须拥有一套高效且严谨的研发管理体系。华为作为全球领先的ICT解决方案提供商,其集成产品开发(IPD, Integrated Product Development)体系与质量管理体系(如ISO 9000系列)的融合实践,...
IPD项目管理   0  
  IPD流程图的7种经典绘制方法详解在产品开发领域,集成产品开发(Integrated Product Development,简称IPD)流程被广泛应用,以提高产品开发的效率和质量。IPD流程图作为这一流程的可视化工具,其绘制方法至关重要。本文将详细介绍七种经典的IPD流程图绘制方法,帮助项目管理人员和团队更好地理解和...
IPD研发管理体系   0  
  IPD流程:企业创新管理的核心引擎在当今快速变化的市场环境中,企业要想持续保持竞争力,就必须不断进行创新。而IPD(Integrated Product Development,集成产品开发)流程作为一种先进的产品开发管理模式,正逐渐成为众多企业提升创新能力、加速产品上市速度、降低开发成本的重要选择。本文将深入探讨IP...
IPD管理   0  
  IPD流程与传统产品开发流程的概述在产品开发领域,企业不断寻求高效、系统的管理方法以确保产品能够顺利从概念转化为市场成功的产品。集成产品开发(Integrated Product Development,简称IPD)流程与传统产品开发流程是两种截然不同的管理理念和方法。传统产品开发流程往往以职能部门为核心,各部门按顺序...
IPD流程中PDCP是什么意思   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用