4 Функции фильтрации в Python из модуля Itertools, о которых вы, вероятно, не знали

4 фильтрационные функции в Python из модуля Itertools, о которых вы, возможно, не знали

 

В Python итераторы помогают вам писать более питонический код и работать более эффективно с длинными последовательностями. Встроенный модуль itertools предоставляет несколько полезных функций, которые создают итераторы. 

Они особенно полезны, когда вы хотите просто пройти по итератору, извлечь элементы из последовательности и обработать их – все это без необходимости хранить их в памяти. Сегодня мы узнаем, как использовать следующие четыре функции фильтрации в itertools:

  • filterfalse
  • takewhile
  • dropwhile
  • islice

Давайте начнем!

 

Перед началом: Заметка о примерах кода

 

В этом учебнике:

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

 

1. filterfalse

 

Если вы программировали на Python некоторое время, вы, вероятно, использовали встроенную функцию filter с синтаксисом:

filter(pred,seq)
# pred: предикатная функция
# seq: любой допустимый итерируемый объект Python

 

Функция filter возвращает итератор, который возвращает элементы из последовательности, для которых предикат возвращает True.

Давайте рассмотрим пример:

nums = list(range(1,11)) #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

def is_even(n):
    return n % 2 == 0

 

Здесь список nums и функция is_even являются последовательностью и предикатом соответственно. 

Чтобы получить список всех четных чисел в nums, мы используем filter следующим образом:

nums_even = filter(is_even, nums)
print(list(nums_even))

 

Output >>> [2, 4, 6, 8, 10]

 

Теперь давайте узнаем о filterfalse. Мы импортируем функцию filterfalse (и все остальные функции, о которых мы будем говорить) из модуля itertools.

Как следует из названия, filterfalse делает противоположное тому, что делает функция filter. Она возвращает итератор, который возвращает элементы, для которых предикат возвращает False. Вот синтаксис для использования функции filterfalse:

from itertools import filterfalse
filterfalse(pred,seq)

 

Функция is_even возвращает False для всех нечетных чисел в nums. Таким образом, список nums_odd, полученный с помощью filterfalse, является списком всех нечетных чисел в nums:

from itertools import filterfalse

nums_odd = filterfalse(is_even, nums)
print(list(nums_odd)) 

 

Output >>> [1, 3, 5, 7, 9]

 

2. takewhile

 

Синтаксис использования функции takewhile таков:

from itertools import takewhile
takewhile(pred,seq)

 

Функция takewhile возвращает итератор, который возвращает элементы до тех пор, пока предикатная функция возвращает True. Она перестает возвращать элементы, когда предикат возвращает False в первый раз.

Для последовательности длины n, если seq[k] – первый элемент, для которого предикатная функция возвращает False, то итератор возвращает seq[0], seq[1],…, seq[k-1].

Рассмотрим следующий список nums и предикатную функцию is_less_than_5. Мы используем функцию takewhile следующим образом:

from itertools import takewhile

def is_less_than_5(n):
    return n < 5

nums = [1, 3, 5, 2, 4, 6]
filtered_nums_1 = takewhile(is_less_than_5, nums)
print(list(filtered_nums_1))

 

Здесь предикат is_less_than_5 возвращает False – в первый раз – для числа 5:

Вывод >>> [1, 3]

 

3. dropwhile

 

Функционально, функция dropwhile делает обратное тому, что делает функция takewhile.

Вот как вы можете использовать функцию dropwhile:

from itertools import dropwhile
dropwhile(pred,seq)

 

Функция dropwhile возвращает итератор, который пропускает элементы, пока предикат возвращает True. Это означает, что итератор не возвращает ничего, пока предикат в первый раз не вернет False. И как только предикат вернет False, итератор возвращает все последующие элементы последовательности.

Для последовательности длины n, если seq[k] – первый элемент, для которого предикатная функция возвращает False, то итератор возвращает seq[k], seq[k+1],…, seq[n-1].

Давайте использовать ту же последовательность и предикат:

from itertools import dropwhile

def is_less_than_5(n):
    return n < 5

nums = [1, 3, 5, 2, 4, 6]
filtered_nums_2 = dropwhile(is_less_than_5, nums)
print(list(filtered_nums_2))

 

Поскольку предикатная функция is_less_than_5 возвращает False – в первый раз – для элемента 5, мы получаем все элементы последовательности, начиная с 5:

Вывод >>> [5, 2, 4, 6]

 

4. islice

 

Вы уже знакомы с срезанием итерируемых объектов в Python, таких как списки, кортежи и строки. Синтаксис среза выглядит так: iterable[start:stop:step].

Однако у этого подхода с срезанием есть следующие недостатки:

  • При работе с большими последовательностями каждый срез или подпоследовательность – это копия, которая занимает память. Это может быть неэффективно.
  • Поскольку шаг также может принимать отрицательные значения, использование значений начала, конца и шага влияет на читаемость кода.

Функция islice решает указанные выше ограничения:

  • Она возвращает итератор.
  • Она не позволяет использовать отрицательные значения для шага.

Вы можете использовать функцию islice следующим образом:

from itertools import islice
islice(seq,start,stop,step)

 

Вот несколько различных способов использования функции islice:

  • Использование islice(seq, stop) возвращает итератор для среза seq[0], seq[1],…, seq[stop - 1].
  • Если вы указываете значения начала и конца: islice(seq, start, stop), функция возвращает итератор для среза seq[start], seq[start + 1],…, seq[start + stop - 1].
  • Когда вы указываете аргументы начала, конца и шага, функция возвращает итератор для среза seq[start], seq[start + step], seq[start + 2*step],…, seq[start + k*step]. При этом должно выполняться условие start + k*step < stop, а start + (k+1)*step >= stop.

Давайте рассмотрим пример списка, чтобы лучше понять:

nums = list(range(10)) #[0,1, 2, 3, 4, 5, 6, 7, 8, 9]

 

Теперь давайте воспользуемся функцией islice с помощью изученного синтаксиса.

 

Использование только значения конца

 

Давайте укажем только индекс конца:

from itertools import islice

# только конец
sliced_nums = islice(nums, 5)
print(list(sliced_nums)) 

 

И вот результат:

Output >>> [0, 1, 2, 3, 4]

 

Использование начального и конечного значений

 

Здесь мы используем и начальное, и конечное значения:

# начало и конец
sliced_nums = islice(nums, 2, 7)
print(list(sliced_nums))

 

Срез начинается с индекса 2 и распространяется до индекса 7 (не включая его): 

Output >>> [2, 3, 4, 5, 6]

 

Использование начального, конечного и шагового значений

 

Когда мы используем начальное, конечное и шаговое значения:

# с использованием начала, конца и шага
sliced_nums = islice(nums, 2, 8, 2)
print(list(sliced_nums))  

 

Мы получаем срез, начинающийся с индекса 2, распространяющийся до индекса 8 (не включая его), с шагом 2 (возвращая каждый второй элемент).

Output >>> [2, 4, 6]

 

Завершение

 

Я надеюсь, что этот учебник помог вам понять основы функций фильтрации itertools. Вы увидели несколько простых примеров, чтобы лучше понять работу этих функций. Далее вы можете изучить, как работают генераторы, генераторные функции и выражения, как эффективные итераторы python.     Bala Priya C – разработчик и технический писатель из Индии. Ей нравится работать на пересечении математики, программирования, науки о данных и создания контента. Ее интересы и экспертиза включают DevOps, науку о данных и обработку естественного языка. Она любит читать, писать, кодировать и кофе! В настоящее время она работает над изучением и делится своими знаниями с сообществом разработчиков, создавая учебники, руководства, мнения и многое другое.