Функция filter для отбора значений итерируемых объектов

Курс по Python: https://stepik.org/course/100707

На прошлом занятии мы с вами детально познакомились с функцией map(). Здесь же будем говорить о похожей функции filter():

filter(func, *iterables)

которая служит для фильтрации (отбора) элементов указанного итерированного объекта.

Работает она очень просто. Если функция func возвращает для текущего значения элемента True, то он будет возвращен, а при False – отброшен. Например, у нас имеется список из целых чисел:

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

и мы хотим выбрать из него только четные значения. Для этого запишем функцию filter(), следующим образом:

b = filter(lambda x: x % 2 == 0, a)
print(b)

После запуска программы, видим, что переменная b ссылается на специальный объект filter. В действительности, это итератор, который можно перебрать с помощью функции next():

print(next(b))
print(next(b))

В результате, увидим в консоли первые два четных значения из списка. Переберем их все с помощью цикла for:

for x in b:
    print(x, end=" ")

Или, можно сформировать новый список с помощью функции list():

c = list(b)
print(c)

Или кортеж:

c = tuple(b)

И так далее. Можно перебрать итератор любыми известными нам функциями и операторами.

Иногда алгоритм обработки текущего значения может быть нетривиальным и записать его в лямбда-функцию довольно сложно. Ну, например, проверить, является ли число простым или нет. Напомню, что простым называется любое натуральное число, которое делится только на себя и на единицу. Такую проверку лучше вынести в отдельную функцию:

def is_prost(x):
    d = x-1
    if d < 0:
        return False
    
    while d > 1:
        if x % d == 0:
            return False
        d -= 1
 
    return True

А, затем, указать ее в filter():

b = filter(is_prost, a)

На выходе получим только простые числа из списка. Конечно, это не самый лучший способ нахождения простых чисел, но как пример функции для filter() вполне подходит.

Функцию filter можно применять с любыми типами данных, например, строками. Пусть у нас имеется вот такой кортеж:

lst = ("Москва", "Рязань1", "Смоленск", "Тверь2", "Томск")
b = filter(str.isalpha, lst)
 
for x in b:
    print(x)

и мы вызываем метод строк isalpha(), который возвращает True, если в строке только буквенные символы. В результате в консоли увидим:

Москва Смоленск Тверь Томск

Вложенные вызовы функции filter()

Так как функция filter() возвращает итератор и в качестве второго аргумента также можно указывать любой итерируемый объект, то мы можем одну функцию filter() вложить в другую:

Например, первая (вложенная) функция filter() будет формировать простые числа, а вторая (внешняя) выбирать из простых чисел только нечетные. В нашей программе для этого достаточно прописать еще одну строчку:

b2 = filter(lambda x: x % 2 != 0, b)

и вывести полученный список:

c = tuple(b2)
print(c)

Или, то же самое можно реализовать и так:

b2 = filter(lambda x: x % 2 != 0, filter(is_prost, a))

Мы здесь вторым аргументом передаем результат работы вложенной функции filter(). И таких вложений можно делать сколько угодно. Хотя на практике, как правило, все эти вложения можно легко свести к одному простому вызову функции filter(), сформировав более сложное условие. Обычно, так и поступают. То есть, опять же, в нашем случае вместо этой вложенности можно немного модифицировать саму функцию is_prost(), следующим образом:

def is_prost(x):
    d = x-1
    if d < 0 or x % 2 == 0:
        return False
 
    while d > 1:
        if x % d == 0:
            return False
        d -= 1
 
    return True

Мы здесь вначале прописали составное условие if d < 0 or x % 2 == 0, которое сразу возвратит False для четного значения x. И при этом, программа будет работать быстрее.

Вот так работает и используется функция filter() для отбора определенных значений из итерируемых объектов. Для закрепления этого материала пройдите практические задания и переходите к следующему уроку.

Курс по Python: https://stepik.org/course/100707

Видео по теме