Как отфильтровать список по условию в Python?
Есть список чисел, хочу оставить только те, что больше нуля (или только чётные). Делаю через цикл с if и append в новый список, но кажется, что должно быть короче. Как фильтровать список по условию?
2 ответа
Самый питоничный способ — списочное включение (list comprehension) с условием if в конце:
nums = [-2, 5, -1, 8, 0, 3]
positive = [x for x in nums if x > 0] # [5, 8, 3]
evens = [x for x in nums if x % 2 == 0] # [-2, 8, 0]
Читается слева направо: «возьми x из nums, если выполняется условие». Это короче и быстрее, чем цикл с append.
Можно сразу и преобразовывать элемент, и фильтровать:
# квадраты только положительных
[x**2 for x in nums if x > 0] # [25, 64, 9]
Альтернатива — встроенная filter():
positive = list(filter(lambda x: x > 0, nums))
Но filter возвращает ленивый объект, его надо оборачивать в list(), и lambda многословнее. В современном Python списочное включение обычно предпочтительнее.
Важно про порядок if и for:
- Условие-фильтр ставится после
for:[x for x in nums if x > 0]. - А вот тернарное условие (когда нужно заменять значение, а не отбрасывать) ставится перед
for:[x if x > 0 else 0 for x in nums].
Это разные конструкции, их часто путают: первая выкидывает элементы, вторая оставляет все, но меняет.
Если условий несколько, их можно объединять через and/or:
[x for x in nums if x > 0 and x % 2 == 0] # положительные И чётные
А для фильтрации списка словарей условие просто обращается к ключу:
adults = [p for p in people if p['age'] >= 18]
Когда условие становится сложным, вынесите его в отдельную функцию def is_ok(x): ... и пишите [x for x in nums if is_ok(x)] — так читаемее, чем громоздкое выражение в скобках.