使用List Comprehensions替换字符串

时间:2018-04-23 08:29:24

标签: python string list list-comprehension

是否可以使用List Comprehensions执行此示例:

a = ['test', 'smth']
b = ['test Lorem ipsum dolor sit amet',
     'consectetur adipiscing elit',
     'test Nulla lectus ligula',
     'imperdiet at porttitor quis',
     'smth commodo eget tortor', 
     'Orci varius natoque penatibus et magnis dis parturient montes']


for s in a:
    b = [el.replace(s,'') for el in b]

我想要的是从句子列表中删除特定单词。我可以使用循环来做,但我想可以使用一些单行解决方案。

我尝试过类似的事情:

b = [[el.replace(s,'') for el in b] for s in a ]

但是出错了

我得到了很多高质量的答案,但现在我有更复杂的问题:如果我想使用单词组合怎么办?

a = ['test', 'smth commodo']

谢谢你的答案! 我对所有解决方案进行了速度测试,结果如下: 我的意思是100次计算(除了最后一次,它等待的时间太长了。)

                      b=10 a=2   |  b=9000 a=2 | b=9000 a=100 | b=45k a=500
---------------------------------+-------------+--------------+---------------
COLDSPEED solution:   0.0000206  |  0.0311071  |  0.0943433   |  4.5012770
Jean Fabre solution:  0.0000871  |  0.1722340  |  0.2635452   |  5.2981001
Jpp solution:         0.0000212  |  0.0474531  |  0.0464369   |  0.2450547
Ajax solution:        0.0000334  |  0.0303891  |  0.5262040   | 11.6994496
Daniel solution:      0.0000167  |  0.0162156  |  0.1301132   |  6.9071504
Kasramvd solution:    0.0000120  |  0.0084146  |  0.1704623   |  7.5648351

我们可以看到Jpp解决方案是最快的但我们无法使用它 - 它是所有其他无法解决单词组合的解决方案(我已经写过他并希望他会改进他的答案!)。所以看起来@cᴏʟᴅsᴘᴇᴇᴅ的解决方案在大数据集上是最快的。

7 个答案:

答案 0 :(得分:4)

你所拥有的东西没有任何问题,但是如果你想要清理一些东西并且性能不重要,那么编译一个正则表达式模式并在循环中调用sub

>>> import re
>>> p = re.compile(r'\b({})\b'.format('|'.join(a)))
>>> [p.sub('', text).strip() for text in b]

['Lorem ipsum dolor sit amet',
 'consectetur adipiscing elit',
 'Nulla lectus ligula',
 'imperdiet at porttitor quis',
 'commodo eget tortor',
 'Orci varius natoque penatibus et magnis dis parturient montes'
]

<强>详情
您的模式将如下所示:

\b    # word-boundary - remove if you also want to replace substrings
(
test  # word 1
|     # regex OR pipe
smth  # word 2 ... you get the picture
)
\b    # end with another word boundary - again, remove for substr replacement

这是编译的正则表达式模式匹配器:

>>> p
re.compile(r'\b(test|smth)\b', re.UNICODE)

另一个考虑因素是你的替换字符串本身是否包含可以由正则表达式引擎解释的字符 - 而不是被视为文字 - 这些是正则表达式元字符,并且您可以在构建模式时转义它们。这是使用re.escape完成的。

p = re.compile(r'\b({})\b'.format(
    '|'.join([re.escape(word) for word in a]))
)

当然,请记住,对于更大的数据和更多的替换,正则表达式和字符串替换都变得乏味。考虑使用更适合大型操作的东西,例如flashtext

答案 1 :(得分:3)

如果列表很大,如果要删除的单词列表很大("\btest\b|\bsmth\b"),构建正则表达式的ORed列表(如O(n))可能会很长。正则表达式测试第一个单词,然后测试第二个单词......

我建议你使用{em>替换函数使用set进行单词查找。如果找不到,则返回单词本身,否则不返回任何单词:

a = {'test', 'smth'}
b = ['test Lorem ipsum dolor sit amet',
     'consectetur adipiscing elit',
     'test Nulla lectus ligula',
     'imperdiet at porttitor quis',
     'smth commodo eget tortor',
     'Orci varius natoque penatibus et magnis dis parturient montes']

import re

result = [re.sub(r"\b(\w+)\b", lambda m : "" if m.group(1) in a else m.group(1),c) for c in b]

print(result)
  

[&#39; Lorem ipsum dolor sit amet&#39;,&#39; consectetur adipiscing elit&#39;,&#39; Nulla lectus ligula&#39;,&#39;在porttitor quis&#39;,&#39;商品eget tortor&#39; Orci varius natoque penatibus et magnis dis parturient montes&#39;]

现在,如果你的&#34;单词&#34;要替换包含由2个单词组成的字符串,此方法不起作用,因为\w不匹配空格。第二遍可以在&#34;单词&#34;由2个单词组成:

a = {'lectus ligula', 'porttitor quis'}

并将result注入类似的过滤器,但显式为2个字匹配:

result = [re.sub(r"\b(\w+ ?\w+)\b", lambda m : "" if m.group(1) in a else m.group(1),c) for c in result]

所以2次通过,但如果单词列表很大,它仍然比详尽的正则表达式快。

答案 2 :(得分:2)

这是使用setstr.joinstr.splitstr.strip的替代方法。

a_set = set(a)

b = [[' '.join([word if word not in a_set else ''
                for word in item.split()]).strip()]
     for item in b]

# [['Lorem ipsum dolor sit amet'],
#  ['consectetur adipiscing elit'],
#  ['Nulla lectus ligula'],
#  ['imperdiet at porttitor quis'],
#  ['commodo eget tortor'],
#  ['Orci varius natoque penatibus et magnis dis parturient montes']]

答案 3 :(得分:1)

您可以使用地图和正则表达式。

import re
a = ['test', 'smth']
b = ['test Lorem ipsum dolor sit amet',
     'consectetur adipiscing elit',
     'test Nulla lectus ligula',
     'imperdiet at porttitor quis',
     'smth commodo eget tortor', 
     'Orci varius natoque penatibus et magnis dis parturient montes']

pattern=r'('+r'|'.join(a)+r')'
b=list(map(lambda x: re.sub(pattern,r'',x).strip(),b))

答案 4 :(得分:1)

作为纯粹的功能方法(主要是出于教育目的),是利用partial模块中的reducefunctools函数以及map来应用替换函数你的字符串列表。

In [48]: f = partial(reduce, lambda x, y: x.replace(y + ' ', ''), a)

In [49]: list(map(f, b))
Out[49]: 
['Lorem ipsum dolor sit amet',
 'consectetur adipiscing elit',
 'Nulla lectus ligula',
 'imperdiet at porttitor quis',
 'commodo eget tortor',
 'Orci varius natoque penatibus et magnis dis parturient montes']

此外,如果a中的项目数量不是很大,则多次重复replace()并没有错。在这种情况下,一种非常优化和直接的方法是使用两个replace如下:

In [54]: [line.replace(a[0] + ' ', '').replace(a[1] + ' ', '') for line in b]
Out[54]: 
['Lorem ipsum dolor sit amet',
 'consectetur adipiscing elit',
 'Nulla lectus ligula',
 'imperdiet at porttitor quis',
 'commodo eget tortor',
 'Orci varius natoque penatibus et magnis dis parturient montes']

答案 5 :(得分:1)

另一种可能性是加入所有单词组合,然后将\s替换为| re.sub

import re
b = ['test Lorem ipsum dolor sit amet',
 'consectetur adipiscing elit',
 'test Nulla lectus ligula',
 'imperdiet at porttitor quis',
 'smth commodo eget tortor', 
 'Orci varius natoque penatibus et magnis dis parturient montes']
a = ['test', 'smth commodo']
replaced_strings = [re.sub(re.sub('\s', '|', ' '.join(a)), '', i) for i in b]

输出:

[' Lorem ipsum dolor sit amet', 'consectetur adipiscing elit', ' Nulla lectus ligula', 'imperdiet at porttitor quis', '  eget tortor', 'Orci varius natoque penatibus et magnis dis parturient montes']

要删除其他空格,请应用额外的通道:

new_data = [re.sub('^\s+', '', i) for i in replaced_strings]

输出:

['Lorem ipsum dolor sit amet', 'consectetur adipiscing elit', 'Nulla lectus ligula', 'imperdiet at porttitor quis', 'eget tortor', 'Orci varius natoque penatibus et magnis dis parturient montes']

答案 6 :(得分:0)

您可能正在寻找:

[el.replace(a[0],'').replace(a[1],'') for el in b]

如果你想删除空格,那么使用strip()

[el.replace(a[0],'').replace(a[1],'').strip() for el in b]

希望这会有所帮助......