从列表中删除以特定字符开头的元素

时间:2015-01-05 01:56:58

标签: python list

我试图从字符串中删除所有提及的内容,我想知道是否有更快的方法来执行此操作?

text = "hey @foo say hi to @bar"
textsplit = text.split()
n = -1
ts2 = textsplit
for x in textsplit:
    n += 1
    if x[0]== "@":
        del ts2[n]
text = ' '.join(ts2)

提前致谢。 (这有点像Removing elements from a list containing specific characters,但这个有点不同。)

6 个答案:

答案 0 :(得分:3)

这与您的代码相同:

' '.join(x for x in text.split() if not x.startswith('@'))

答案 1 :(得分:1)

使用re模块和正则表达式,这个怎么样:

print(" ".join(re.sub('^@\w+', '', w) for w in text.split()))

答案 2 :(得分:1)

这更简单,更快捷:

text = "hey @foo say hi to @bar"
newtext = ' '.join([i for i in text.split() if not i.startswith('@')])

答案 3 :(得分:1)

text = "hey @foo say hi to @bar"
newtext = re.sub(' @[!\w]+', '', text)

无需使用任何循环,只需使用正则表达式。

答案 4 :(得分:0)

我按照@elyase和@ chris-johnson的答案来解答你应该使用的实际简单漂亮的代码。

@ elyase的答案更简单,但我认为@ chris-johnson可能会因join的工作原因而略微提高效率。 @ elyase的代码创建了一个生成器对象,然后join会在运行之前将其转换为列表,我认为这比仅仅创建一个列表要花费更多。但这是一个次要的优化点。

我刚刚在示例代码中发现了一些代码气味,所以想要指出它们。

text = "hey @foo say hi to @bar"
textsplit = text.split()
n = -1
ts2 = textsplit # code smell 1
for x in textsplit:
    n += 1 # code smell 2
    if x[0]== "@":
        del ts2[n] # code smell 3
text = ' '.join(ts2)

代码气味1 :我想你想用ts2 = textsplit创建一个列表的副本,但这并没有发生。您只需为textsplit引用的列表创建另一个名称,因此更改ts2将更改textsplit,反之亦然。您可以ts2 = textsplit[:]制作非嵌套列表的副本。

代码气味2 :您正在创建变量n并通过在每次迭代时手动递增将其用作索引。如果您正在做的事情,请改用for n, x in enumerate(textsplit)

代码气味3 :这里有两件事:

  1. 因为您没有复制textsplit,所以您可以循环遍历列表并立即修改它 - 不惜一切代价避免这种情况,这会导致很难理解的错误。
  2. 即使ts2是副本,此行也存在问题,因为当您删除ts2中的元素时,索引会被抛出不同步状态。在您的示例中,在删除' @ foo'之后,索引现在关闭一个,因此尝试访问/删除' @ bar'使用ts2[n]将抛出一个IndexError。如果您要参与索引操作,则每次删除项目时都需要递减n
  3. 但一般来说,索引twiddling是许多错误的来源。如果你不必这样做,就不要这样做。在Python中,你通常不必这样做。

答案 5 :(得分:0)

在我看来,所有其他答案都在假设您希望删除@...子字符串并在不同字词(或{以外的字符集)之间保持' '的分隔的情况下运行{1}}),如您的代码所示。但是,这个问题并没有明确指出这是一个目标。而且,既然有可能出现(不要问我)这种行为不正确的情况,我们就去吧!

编辑:现在可读且灵活(与旧代码 - 高尔夫版本相比)

我原来的帖子有点傻,因为代码真的不适合制作;它有效,但就是这样。现在,这可以毫不费力地完成三种类型的子串减法,尽管使用正则表达式可能会做得更好(在那里不太经验)。

' '

只有一个text = "hey @foo say hi to @bar" 的常规版本,用于分隔剩余的单词

' '

仅删除指定的子字符串(不删除任何其他空格)

newText = ''.join(
    text[i] if text.rfind('@', 0, i+2) <= text.rfind(' ', 0, i+1) else
    '' for i in xrange(len(text)))

>>> 'hey say hi to'

将子字符串转换为空格

newText = ''.join(
    text[i] if text.rfind('@', 0, i+1) <= text.rfind(' ', 0, i+1) else
    '' for i in xrange(len(text)))

>>> 'hey  say hi to '

希望这有所帮助,不知何故!