Фильтрация списков в Python — функция filter
Помимо сортировки частым действием по отношению к спискам (или другим составным объектам) является их фильтрация. Например, надо убрать из списка отрицательные значения, или пустые строки, или оставить в нем только объекты с определенными свойствами.
В Python для решения подобных задач достаточно написать небольшой код. Пусть из смешанного списка требуется отфильтровать только числа. Код без "синтаксического сахара" будет выглядеть примерно так:
a = ['one', 5, 'two', 4.22, 8, 'j', 0.35] b = [] for item in a: if type(item) in (int, float): b.append(item) print(b)
Результат:
[5, 4.22, 8, 0.35]
Здесь фильтрация выполняется в цикле for. Поскольку цикл достаточно прост, мы можем заменить его списочным выражением:
a = ['one', 5, 'two', 4.22, 8, 'j', 0.35] b = [item for item in a if type(item) in (int, float)] print(b)
Однако это не всё. В Python есть функция filter, которая непосредственно предназначена для решения задач фильтрации. Он принимает два аргумента: первый – функцию, второй – итерируемый объект (последовательность — строки, списки и кортежи, итератор или объект, поддерживающий итерацию). В этом уроке вторым аргументом мы будем передавать только списки.
Функция, которая передается первым аргументом в filter, вызывается на каждый элемент списка. Если эта функция возвращает что угодно, но не объекты None, False и их эквиваленты (0, [], '' и т. п.), то переданный ей текущий элемент списка проходит фильтрацию, он остается.
В filter можно передавать как обычную, так и лямбда-функцию. Рассмотрим сначала пример с обычной функцией:
def numbers(item): if type(item) in (int, float): return True else: return False a = ['one', 5, 'two', 4.22, 8, 'j', 0.35] b = filter(numbers, a) print(list(b))
Обратим внимание, функция filter возвращает не список, а итератор. Для простоты вывода на экран мы преобразовываем его в список.
В функции numbers мы прописываем ветку else для ясности кода. Однако ее можно опустить.
def numbers(item): if type(item) in (int, float): return True
Фильтрация и в этом случае будет работать также. Почему? Когда в numbers передается не число, выражение return True не выполняется. Получается, что функция ничего не возвращает. На самом деле в таких случаях функция возвращает объект None. В свою очередь для функции filter что None, что False – это сигнал отбросить элемент.
Заменим функцию numbers lambda-выражением:
a = ['one', 5, 'two', 4.22, 8, 'j', 0.35] b = filter(lambda item: type(item) in (int, float), a) print(list(b))
Выражение type(item) in (int, float) логическое, оно возвращает либо True, либо False.
Функция filter в качестве первого аргумента может принимать не только другую функцию, но и объект None. В этом случае элементы списка будут оцениваться сами по себе как True или False (или их эквиваленты). В примере ниже из первого списка будут изъяты нули, из второго – пустые строки.
a = [8, -1, 0, 3, 0] b = ['a', 'b', '', 'dd'] f_a = filter(None, a) f_b = filter(None, b) print(list(f_a)) print(list(f_b))
Результат:
[8, -1, 3] ['a', 'b', 'dd']
Практическая работа
Пользователь вводит два натуральных числа, первое больше второго. Используя функцию filter, вывести на экран все натуральные числа, кратные второму числу и не превышающие первое. Например, были введены 10 и 3. Вывод: 3, 6, 9.