如何在列表推导中使用重新匹配对象

Bre*_*ugh 41 python regex list-comprehension

我有一个函数从字符串列表中挑出块并将它们作为另一个列表返回:

def filterPick(lines,regex):
    result = []
    for l in lines:
        match = re.search(regex,l)
        if match:
            result += [match.group(1)]
    return result
Run Code Online (Sandbox Code Playgroud)

有没有办法将其重新表述为列表理解?显然它是相当清楚的; 只是好奇.


感谢那些贡献的人,特别提到了@Alex.这是我最终得到的浓缩版本; 正则表达式匹配方法作为"预先提升"参数传递给filterPick:

import re

def filterPick(list,filter):
    return [ ( l, m.group(1) ) for l in list for m in (filter(l),) if m]

theList = ["foo", "bar", "baz", "qurx", "bother"]
searchRegex = re.compile('(a|r$)').search
x = filterPick(theList,searchRegex)

>> [('bar', 'a'), ('baz', 'a'), ('bother', 'r')]
Run Code Online (Sandbox Code Playgroud)

Ale*_*lli 70

[m.group(1) for l in lines for m in [regex.search(l)] if m]
Run Code Online (Sandbox Code Playgroud)

"技巧"是for m in [regex.search(l)]部分 - 这就是你如何"分配"一个你需要在列表理解中多次使用的值 - 添加这样一个子句,其中对象"迭代"在单项列表上包含您要"分配"它的一个值.有些人认为这在风格上是可疑的,但我觉得它有时候很实用.

  • @AlexMartelli,我发现嵌套理解比"for hack"更具可读性:`search = re.compile('...').search; out = [m.group(1)for m in map(search,lines)if m]`你可以使用嵌套括号,但在这种情况下map()也是可读的,因为变换器是一个简单的可调用的,它实际上更快!(比使用元组的hack快33%,**比使用列表的hack快40%,比使用括号的嵌套列表理解快15%.)使用中等复杂的正则表达式测量''(a.*b.*c)'',即O(n²),在一个巨大的文件名列表中. (4认同)

Ign*_*ams 10

return [m.group(1) for m in (re.search(regex, l) for l in lines) if m]
Run Code Online (Sandbox Code Playgroud)


Wol*_*lph 7

它可以缩短一点

def filterPick(lines, regex):
    matches = map(re.compile(regex).match, lines)
    return [m.group(1) for m in matches if m]
Run Code Online (Sandbox Code Playgroud)

你可以将它全部放在一行中,但这意味着你必须匹配每一行两次,效率会有点低.

  • 不,不需要两次匹配每一行,看看我的答案. (2认同)

Xav*_*hot 5

开始Python 3.8,并引入赋值表达式(PEP 572):=运算符),可以在列表理解中使用局部变量,以避免多次调用相同的表达式:

# items = ["foo", "bar", "baz", "qurx", "bother"]
[(x, match.group(1)) for x in items if (match := re.compile('(a|r$)').search(x))]
# [('bar', 'a'), ('baz', 'a'), ('bother', 'r')]
Run Code Online (Sandbox Code Playgroud)

这:

  • 将 的求值命名re.compile('(a|r$)').search(x)为变量match(要么是None一个Match对象)
  • match就地使用此命名表达式(None或者 a Match)来过滤掉不匹配的元素
  • 并通过提取第一组 ( ) 来重新使用match映射值match.group(1)