Python能否用any/all替换内层循环高效移除列表含标点元素
问题
现有需求为移除列表中包含指定标点符号的单词,初始双层for循环实现代码如下:
PUNCT_CHARS = { '(', ')', ',', ',', '、', ':', ':', '[', ']', '#'} words = ['a', '#good', 'student'] for word in words.copy(): for char in PUNCT_CHARS: if char in word: words.remove(word) break print(words) # 输出结果:['a', 'student']
咨询是否可以使用any()或all()函数替换第二层for循环,提升代码执行效率。
解答
完全可以用any()替换第二层循环,不推荐使用all(),原因如下:
any()的短路判断逻辑和原有手动break的逻辑完全一致:只要遍历到第一个满足条件的元素就立刻终止判断,不会做多余遍历,不会改变原有逻辑的正确性any()是C层面实现的内置函数,比纯Python写的内层for循环执行速度更快,确实能带来效率提升all()的逻辑是判断所有元素都满足条件才返回真值,和「只要存在任意一个标点就移除单词」的需求不匹配,无法直接替换
替换后的等价写法
如果保留原有原地修改列表的逻辑,替换后代码如下:
PUNCT_CHARS = { '(', ')', ',', ',', '、', ':', ':', '[', ']', '#'} words = ['a', '#good', 'student'] for word in words.copy(): if any(char in word for char in PUNCT_CHARS): words.remove(word) print(words) # 输出:['a', 'student']
更优的效率优化方案
原有实现需要拷贝列表、反复对原列表做remove操作,时间复杂度为O(n²),更推荐直接用列表推导式生成过滤后的新列表,时间复杂度为O(n),执行效率更高:
PUNCT_CHARS = { '(', ')', ',', ',', '、', ':', ':', '[', ']', '#'} words = ['a', '#good', 'student'] words = [word for word in words if not any(char in word for char in PUNCT_CHARS)] print(words) # 输出:['a', 'student']
如果追求极致的判断效率,还可以用集合的isdisjoint()方法替代any(),该方法同样是C层实现,判断逻辑等价(检查单词和标点集合是否没有公共元素,没有则保留单词),开销比生成器形式的any()更低:
words = [word for word in words if PUNCT_CHARS.isdisjoint(word)]
内容的提问来源于stack exchange,提问作者marlon
相关产品推荐
相关产品推荐

