Как использовать повторно сопоставляемые объекты в понимании списка
У меня есть функция для выделения комков из списка строк и возврата их в виде другого списка:
def filterPick(lines,regex):
result = []
for l in lines:
match = re.search(regex,l)
if match:
result += [match.group(1)]
return result
Есть ли способ переформулировать это как понимание списка? Очевидно, это довольно ясно, как есть; просто любопытно.
Спасибо тем, кто внес свой вклад, специально для @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')]
Ответы
Ответ 1
[m.group(1) for l in lines for m in [regex.search(l)] if m]
"трюк" - это часть for m in [regex.search(l)]
- то, как вы "назначаете" значение, которое вам нужно использовать более одного раза, в понимании списка - добавьте только такое предложение, где объект "итерации" над списком с одним элементом, содержащим одно значение, которое вы хотите "назначить" ему. Некоторые считают это стилистически сомнительным, но иногда я считаю это практичным.
Ответ 2
return [m.group(1) for m in (re.search(regex, l) for l in lines) if m]
Ответ 3
Его можно немного сократить
def filterPick(lines, regex):
matches = map(re.compile(regex).match, lines)
return [m.group(1) for m in matches if m]
Вы можете поместить все в одну строку, но это означало бы, что вам придется сопоставлять каждую строку дважды, что было бы немного менее эффективным.
Ответ 4
Начиная с 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)
оценку re.compile('(a|r$)').search(x)
как match
переменной (которая является None
или объектом Match
) - Использует это
match
именованным выражением на месте (None
или Match
), чтобы отфильтровать несоответствующие элементы - И повторно использует
match
в сопоставленном значении, извлекая первую группу (match.group(1)
).
Ответ 5
>>> "a" in "a visit to the dentist"
True
>>> "a" not in "a visit to the dentist"
False
Это также работает с поисковым запросом, который вы просматриваете в списке
`P = 'a', 'b', 'c'
'b' в P` возвращает true