目前在做文本主题提取和分词,遇到一个很有意思的低级问题,同时可以体现一种很普遍的解题思路,现记录下来。
如下,有个list,对,就是这货。
bad_sents = ['此条工单内容显示:该市民反应的问题是']
sents = ['此条工单内容显示:该市民反应的问题是',
'此条工单内容显示:该市民反应的问题是',
'1、问题描述:平潮镇九圩港村停水事宜',
'部门处理']
目标需求:
- ①筛选掉 ‘此条工单内容显示:该市民反应的问题是’;
- ②筛选掉长度小于等于5的记录。
最终大神的指点下的实现代码:
sents = [x for x in sents if x not in bad_sents and len(x) > 5] #列表生成式,膜拜啊
注:如果你没有兴趣读下去,可以到此为止了,后面的是关于我智障解题思路的记录。
解题思路:
刚开始的核心思路是“剔除”不满足条件的记录。于是写下了个新手很容易犯错误的代码,如下:
bad_sents = ['此条工单内容显示:该市民反应的问题是']
for i, sent in enumerate(sents):
print(i,sent)
if sent in bad_sents or len(sent) <= 5:
# 剔除不符合的对象
print(sents.pop(i))
else:
pass
然后查看结果,sents,懵逼了,怎么还有一条记录:’此条工单内容显示:该市民反应的问题是’。
我想,可能是因为有重复对象的原因,pop只会pop出第一个元素(这种想法是错误的),尝试用remove。
代码修改如下:
for sent in sents:
print(sent)
print('####################')
if sent in bad_sents or len(sent) <= 5:
# 剔除不符合的对象
print(sents.remove(sent))
else:
pass
兴冲冲的运行,哎呦,怎么和上面的结果一样。。。。。。
百思不得其解,大神看了一眼,傻啊,怎么能在循环中操作列表呢。你每把一个元素删除出去,列表都会更新成新的列表。也就是说:我在用原列表的index和item(sent)去匹配操作不断变化的新列表!(突然想到了闭包的相关知识:返回函数不要引用任何循环变量,或者后续会发生变化的变量。)
那怎么做呢,需要一个深度copy对象,把原列表保存在sentstmp中。
import copy
sentstmp = copy.deepcopy(sents)
for i, sent in enumerate(sentstmp):
print(sent)
if sent in bad_sents or len(sent) <= 5:
try:
sents.pop(i)
except:
pass
else:
pass
大神啪啪啪就敲出了这段代码,正在我赞叹之余,大神笑了笑,你的思路就不“正常”,为什么不思考“挑出符合条件”的数据呢?来,我给你写一行让你无地自容的代码。
sents = [x for x in sents if x not in bad_sents and len(x) > 5]
我的天,强无敌啊!
————–分割线—————-
后来,我不断的把bad_sents丰富,并觉得可以用正则表达式实现,如下是部分代码:
bad_sents = [r'此条工单内容显示:该市民反应的问题.*'
, r'.*问题描述:市民来电'
, r'.*问题描述:电话接通后'
, r'已按服务规范应答'
, r'市民来电反映:.*下午'
, r'来电时间:\d{4}/\d{1,2}/\d{1,2}\s*\d{1,2}:\d{2}:\d{2}'
, r'..诉求目的.'
]
# 去掉无意义的句子,这段niubility的代码被我小小的更改了下
for bad_sent in bad_sents:
sents = [x for x in sents if re.match(bad_sent, x) is None and len(x) > 2]