首页 > 解决方案 > 如何在不再次计算对象的情况下检查列表理解中的单个输出不为空

问题描述

我正在尝试使用列表推导从字符串列表中删除一些字符。因此,我使用正则表达式删除它们,但正则表达式的输出可能为空。有什么方法可以删除这些输出,而不必在数组上进行额外的循环或再次运行正则表达式?

假设我有以下数组:

>>> example
["a ", "    ", "", "a. &//*-_", " n", "   b   ", "*"]

我想要的输出是:

>>> func(example)
'a#a &//_#n#b'

目前,我有这个函数返回一些接近的东西,我可以再次处理以获得所需的输出,但我想知道是否有任何解决方案而不做第二遍。

def func(example):
    pattern = "[^\w\s\&\/]"
    return "#".join(re.sub(pattern, "", unidecode(tag).lower().strip()) for tag in example)

>>> func(example)
'a###a &//_#n#b#'

我认为的一种可能性如下,但我想知道这是否再次计算字符串的整个处理:

def func2(example):
    pattern = "[^\w\s\&\/]" # The pattern here is not particularly important, I just want to remove some weird characters and keep a couple
    return "#".join(re.sub(pattern, "", unidecode(tag).lower().strip()) for tag in example if re.sub(pattern, "", unidecode(tag).lower().strip()))

>>> func2(example)
'a#a &//_#n#b'

标签: pythonregexlist-comprehension

解决方案


这种通用技术有效:

  1. 创建一个生成器,生成计算两次或更多次的元素;
  2. 在列表理解中使用这个生成器。

在你的情况下:

>>> import re
>>> from unidecode import unidecode
>>> example = ["a ", "    ", "", "a. &//*-_", " n", "   b   ", "*"]
>>> def func3(example):
...     pattern = "[^\w\s\&\/]"
...     return "#".join(x for x in (re.sub(pattern, "", unidecode(tag).lower().strip()) for tag in example) if x)
>>> func3(example)
'a#a &//_#n#b'

(re.sub(pattern, "", unidecode(tag).lower().strip()) for tag in example)是生成器,然后根据计算结果为 的值过滤此生成器True


备注:在您的特定情况下,您还可以使用内置filter

>>> def func4(example):
...     pattern = "[^\w\s\&\/]"
...     return "#".join(filter(None, (re.sub(pattern, "", unidecode(tag).lower().strip()) for tag in example)))
>>> func4(example)
'a#a &//_#n#b'

文档

filter(function, iterable) [...] 如果 function 为 None,则假定身份函数,即,所有为 false 的 iterable 元素都被删除。(强调我的)


推荐阅读