从列表中删除以特定字符开头的元素
remove elements from a list that begin with a specific character
我正在尝试从字符串中删除所有提及任何人的内容,我想知道是否有更快的方法来执行此操作?
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 但这个有点不同。)
这个呢,使用 re 模块和正则表达式:
print(" ".join(re.sub('^@\w+', '', w) for w in text.split()))
这与您的代码相同:
' '.join(x for x in text.split() if not x.startswith('@'))
这个更简单也更快:
text = "hey @foo say hi to @bar"
newtext = ' '.join([i for i in text.split() if not i.startswith('@')])
我遵从@elyase 和@chris-johnson 对您应该使用的实际简单漂亮代码的回答。
@elyase 的回答更简单,但我认为由于 join
的工作方式,@chris-johnson 的回答可能会稍微高效一些。 @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:这里有两件事:
- 因为您没有复制 textsplit,所以您正在遍历一个列表并立即修改它 - 无论如何都要避免这种情况,它会导致异常难以推理的错误。
- 即使 ts2 是副本,这一行也是有问题的,因为当您删除 ts2 中的元素时,索引会变得不同步。在您的示例中,在删除 '@foo' 之后,索引现在减一,因此尝试使用
ts2[n]
access/delete '@bar' 将引发 IndexError。如果你要搞索引twiddling,你需要每删除一个项目就递减n
。
但一般来说,索引调整是许多错误的来源。如果没有必要,请不要这样做。在 Python 中,您通常不必这样做。
text = "hey @foo say hi to @bar"
newtext = re.sub(' @[!\w]+', '', text)
无需使用任何循环,只需使用正则表达式即可。
我突然想到,所有其他答案都假设您希望删除 @...
子字符串并在不同单词(或其他字符集)之间保持 ' '
的分隔比 ' '
),正如您的代码所证明的那样。但是,问题没有明确指出这是 objective。而且,由于可能存在(不要问我)这种行为不正确的情况,我们开始吧!
编辑: 现在可读且灵活(与旧代码版本相比)
我原来的 post 有点傻,因为代码真的不是为生产而设计的;它起作用了,但仅此而已。这现在毫不费力地完成了三种类型的子字符串减法,尽管也许它可以用正则表达式做得更好(在那里没有太多经验)。
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 '
将子字符串转换为空格
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 '
希望这能有所帮助!
我正在尝试从字符串中删除所有提及任何人的内容,我想知道是否有更快的方法来执行此操作?
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 但这个有点不同。)
这个呢,使用 re 模块和正则表达式:
print(" ".join(re.sub('^@\w+', '', w) for w in text.split()))
这与您的代码相同:
' '.join(x for x in text.split() if not x.startswith('@'))
这个更简单也更快:
text = "hey @foo say hi to @bar"
newtext = ' '.join([i for i in text.split() if not i.startswith('@')])
我遵从@elyase 和@chris-johnson 对您应该使用的实际简单漂亮代码的回答。
@elyase 的回答更简单,但我认为由于 join
的工作方式,@chris-johnson 的回答可能会稍微高效一些。 @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:这里有两件事:
- 因为您没有复制 textsplit,所以您正在遍历一个列表并立即修改它 - 无论如何都要避免这种情况,它会导致异常难以推理的错误。
- 即使 ts2 是副本,这一行也是有问题的,因为当您删除 ts2 中的元素时,索引会变得不同步。在您的示例中,在删除 '@foo' 之后,索引现在减一,因此尝试使用
ts2[n]
access/delete '@bar' 将引发 IndexError。如果你要搞索引twiddling,你需要每删除一个项目就递减n
。
但一般来说,索引调整是许多错误的来源。如果没有必要,请不要这样做。在 Python 中,您通常不必这样做。
text = "hey @foo say hi to @bar"
newtext = re.sub(' @[!\w]+', '', text)
无需使用任何循环,只需使用正则表达式即可。
我突然想到,所有其他答案都假设您希望删除 @...
子字符串并在不同单词(或其他字符集)之间保持 ' '
的分隔比 ' '
),正如您的代码所证明的那样。但是,问题没有明确指出这是 objective。而且,由于可能存在(不要问我)这种行为不正确的情况,我们开始吧!
编辑: 现在可读且灵活(与旧代码版本相比)
我原来的 post 有点傻,因为代码真的不是为生产而设计的;它起作用了,但仅此而已。这现在毫不费力地完成了三种类型的子字符串减法,尽管也许它可以用正则表达式做得更好(在那里没有太多经验)。
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 '
将子字符串转换为空格
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 '
希望这能有所帮助!