Фильтрация коллекции
Фильтрация — это отбор тех элементов коллекции, которые соответствуют условию.
Условие принимает один элемент и отвечает True (оставить его) или False (пропустить его). Функция, которая это делает, называется предикатом.
Фильтрация создаёт новый список. Исходный список не изменяется.
В Python фильтруют с помощью спискового включения с частью if: [w for w in words if len(w) > 3]. Оно читается почти как обычная фраза на английском: оставить каждое w, длина которого больше 3.
В Python также есть встроенная функция filter(), которая принимает предикат и список. Она работает, но возвращает ленивый итератор и требует lambda даже для простого условия, поэтому списковое включение обычно понятнее. На этой странице используются включения.
Фильтрация по предикату
Самый простой способ фильтрации — включение, в части if которого находится условие. Python проходит по списку и оставляет каждый элемент, который проходит проверку.
Словари работают так же: словарное включение по items() копирует подходящие пары ключ:значение в новый словарь.
Если условию нужна ещё и позиция элемента, enumerate даёт индекс и значение вместе.
Чтобы оставить элементы, которые не соответствуют условию, поставьте not перед условием. Отдельной функции filter_not в Python нет.
Список может содержать значения разных типов. isinstance(v, str) проверяет, является ли значение строкой. Значение также может быть None, что означает «нет значения»; чтобы пропустить такие элементы, используйте сравнение is not None.
Фильтрация списка
Оставьте только слова длиннее 3 букв. Условие len(w) > 3 стоит в части if включения.
Вывод: полная программа на Python
words = ["one", "two", "three", "four"]
# часть if оставляет только элементы, которые проходят проверку
longer_than_3 = [w for w in words if len(w) > 3]
print(longer_than_3)
Фильтрация словаря
Пройдите по items() и оставьте пары, ключ которых оканчивается на "1", а значение больше 10. endswith() проверяет конец строки.
Вывод: полная программа на Python
numbers_map = {"key1": 1, "key2": 2, "key3": 3, "key11": 11}
# словарное включение по items() фильтрует пары ключ:значение
filtered_map = {k: v for k, v in numbers_map.items() if k.endswith("1") and v > 10}
print(filtered_map)
Фильтрация с использованием индекса
enumerate даёт индекс и значение. Слово остаётся, только если его индекс не равен 0 и в нём меньше 5 букв.
Вывод: полная программа на Python
numbers = ["one", "two", "three", "four"]
# enumerate даёт и индекс, и значение, поэтому условие может использовать оба
filtered_idx = [w for i, w in enumerate(numbers) if i != 0 and len(w) < 5]
print(filtered_idx)
Фильтрация с инвертированным условием
Отбросьте слова из 3 букв или короче. Условие len(w) = 3 инвертируется с помощью not, поэтому остаются только более длинные слова.
Вывод: полная программа на Python
numbers = ["one", "two", "three", "four"]
# filter_not не существует: инвертируйте условие с помощью not
filtered_not = [w for w in numbers if not len(w) <= 3]
print(filtered_not)
Фильтрация по типу
Список содержит None, целое число, две строки и число с плавающей точкой. isinstance(v, str) находит строки. Каждая из них выводится в верхнем регистре.
Вывод: полная программа на Python
numbers = [None, 1, "two", 3.0, "four"]
# isinstance(v, str) спрашивает: является ли это значение строкой?
for v in numbers:
if isinstance(v, str):
print(v.upper())
Удаление значений None
Список содержит строки, но некоторые элементы равны None. Оставьте значения, которые не равны None, с помощью проверки is not None.
Вывод: полная программа на Python
# None означает «нет значения»
nullable_list = [None, "one", None, "two"]
values = [v for v in nullable_list if v is not None]
print(values)
Разбиение
Иногда нужны обе группы: элементы, которые соответствуют условию, и те, которые не соответствуют.
Встроенной функции partition для списков в Python нет. Это делает небольшая вспомогательная функция: она один раз проходит по списку и добавляет каждый элемент либо в список match, либо в список rest. Функция возвращает оба списка, потому что функция в Python может вернуть больше одного значения.
Можно также написать два включения — одно с условием, другое с его отрицанием, — но тогда список обходится дважды; вспомогательная функция делает один проход.
Разделение списка на два
Слова длиннее 3 букв попадают в match; все остальные — в rest. Выводятся оба списка.
Вывод: полная программа на Python
def partition(items, test):
match, rest = [], []
for v in items:
if test(v):
match.append(v)
else:
rest.append(v)
return match, rest
numbers = ["one", "two", "three", "four"]
match, rest = partition(numbers, lambda w: len(w) > 3)
print(match)
print(rest)
Проверка предикатов
Иногда нужны не сами подходящие элементы, а только ответ «да» или «нет». Для этого в Python есть встроенные функции:
- any: проходит ли проверку хотя бы один элемент? На это отвечает
any(). - none: не проходит ли проверку ни один элемент? Поставьте
notпередany(). - all: проходит ли проверку каждый элемент? На это отвечает
all().
Обе функции принимают последовательность значений True/False, поэтому им передают выражение-генератор, например w.endswith("e") for w in numbers. any() останавливается, как только находит совпадение.
Без условия вопрос «есть ли вообще элементы?» — это len(numbers) > 0, а «нет ли вообще элементов?» — это len(numbers) == 0.
Для пустого списка all() возвращает True. В нём нет элемента, который не проходит проверку, поэтому проверка никогда не нарушается. Это называется бессодержательной истиной.
any
Проверьте, оканчивается ли хотя бы одно слово на "e", а затем проверьте, есть ли в списке вообще хоть один элемент.
Вывод: полная программа на Python
numbers = ["one", "two", "three", "four"]
# any() равно True, если хотя бы один элемент проходит проверку
print(any(w.endswith("e") for w in numbers))
# «есть ли вообще элементы?» — это просто проверка длины
print(len(numbers) > 0)
none
Проверьте, что ни одно слово не оканчивается на "a", а затем проверьте, пуст ли список.
Вывод: полная программа на Python
numbers = ["one", "two", "three", "four"]
# «none» — противоположность «any»: ни один элемент не проходит проверку
print(not any(w.endswith("a") for w in numbers))
# «нет ли вообще элементов?» — это просто проверка длины
print(len(numbers) == 0)
all
Проверьте, оканчивается ли каждое слово на "e". Затем вызовите all() для пустого списка, что даёт True.
Вывод: полная программа на Python
numbers = ["one", "two", "three", "four"]
empty = []
# all() равно True, только если каждый элемент проходит проверку
print(all(w.endswith("e") for w in numbers))
# в пустом списке нет элемента, который не проходит проверку, поэтому all() равно True
print(all(w.endswith("e") for w in empty))