Как использовать повторяющиеся объекты в понимании списка - PullRequest
41 голосов
/ 13 марта 2010

У меня есть функция, чтобы выбрать комки из списка строк и вернуть их в виде другого списка:

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

Есть ли способ переформулировать это как понимание списка? Очевидно, это довольно ясно, как есть; просто любопытно.


Спасибо тем, кто внес свой вклад, особое упоминание для @Alex. Вот сжатая версия того, чем я закончил; метод сопоставления с регулярным выражением передается в filterPick в качестве параметра «pre-hoisted»:

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')]

Ответы [ 5 ]

70 голосов
/ 13 марта 2010
[m.group(1) for l in lines for m in [regex.search(l)] if m]

«Уловка» - это часть for m in [regex.search(l)] - это то, как вы «присваиваете» значение, которое вам нужно использовать более одного раза, в пределах понимания списка - добавьте именно такое предложение, где объект «повторяется» поверх списка из одного элемента, содержащего одно значение, которое вы хотите «присвоить» ему. Некоторые считают это стилистически сомнительным, но иногда я нахожу это практичным.

10 голосов
/ 13 марта 2010
return [m.group(1) for m in (re.search(regex, l) for l in lines) if m]
7 голосов
/ 13 марта 2010

Может быть немного укорочено

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

Вы можете поместить все это в одну строку, но это будет означать, что вам придется сопоставлять каждую строку дважды, что будет немного менее эффективно.

1 голос
/ 27 апреля 2019

Начиная с 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')]

Это:

  • Называет оценку re.compile('(a|r$)').search(x) как переменную match (которая является либо None, либо Match объектом)
  • Использует это match именованное выражение на месте (None или Match), чтобы отфильтровать несоответствующие элементы
  • И повторно использует match в сопоставленном значении, извлекая первую группу (match.group(1)).
0 голосов
/ 17 ноября 2012
>>> "a" in "a visit to the dentist" 
True 
>>> "a" not in "a visit to the dentist" 
False

Это также работает с поисковым запросом, который вы ищете в списке

`P = 'a', 'b', 'c'

'b' в P` возвращает true

...