Концепции map, filter и reduce меняют правила игры. Использование этих методов выходит за рамки Python и является важным навыком на будущее.

Основы

Map, filter и reduce - это функции, которые помогут вам обрабатывать все виды коллекций. Они лежат в основе современных технологий, таких как Spark и различных других фреймворков для обработки и хранения данных. Но они также могут быть очень мощными помощниками при работе с ванильным Python.

карта

Карта - это функция, которая принимает в качестве входных данных коллекцию, например. список ["бекон", "тост", "яйцо"] и функция, например верхний (). Затем он переместит каждый элемент коллекции через эту функцию и создаст новую коллекцию с тем же количеством элементов. Давайте посмотрим на пример

map_obj = map(str.upper,['bacon','toast','egg'])
print(list(map_obj))
>>['BACON', 'TOAST', 'EGG']

Здесь мы использовали функцию map (some_function, some_iterable) в сочетании с верхней функцией (эта функция использует каждый символ строки с заглавной буквы). Как мы видим, мы создали для каждого элемента во входном списке другой элемент в выходном списке. На выходе мы всегда получаем то же количество элементов, что и помещаем в него! Здесь мы отправляем 3 на вход и получаем 3 на выходе, поэтому мы называем это функцией от N до N. Давайте посмотрим, как это можно использовать.

def count_letters(x):
    return len(list(x))
map_obj = map(count_letters,['bacon','toast','egg'])
print(list(map_obj))
>>[6, 5, 3]

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

map_obj = map(lambda x:len(list(x)),['bacon','toast','egg'])
print(list(map_obj))
>>[6, 5, 3]

Лямбда-выражение - это просто сокращенная запись для определения функции. Если вы не знакомы с ними, вы можете узнать, как они работают, здесь. Однако из следующих примеров должно быть довольно легко понять, как они работают.

Фильтр

В отличие от Map, которая является функцией от N до N. Фильтр - это функция от N до M, где N≥M. Это означает, что это уменьшает количество элементов в коллекции. Другими словами, он их фильтрует! Как и в случае с картой, используется запись filter (some_function, some_collection). Давайте проверим это на примере.

def has_the_letter_a_in_it(x):
    return 'a' in x
# Let's first check out what happens with map
map_obj = map(has_the_letter_a_in_it,['bacon','toast','egg'])
print(list(map_obj))
>>[True,True,False]
# What happens with filter?
map_obj = filter(has_the_letter_a_in_it,['bacon','toast','egg'])
print(list(map_obj))
>>['bacon', 'toast']

Как мы видим, это уменьшает количество элементов в списке. Он делает это путем вычисления возвращаемого значения для функции has_the_letter_a_in_it () и возвращает только те значения, для которых выражение возвращает Истина.

Опять же, это выглядит намного сексуальнее, если использовать нашу любимую лямбду!

map_obj = filter(lambda x: 'a' in x, ['bacon','toast','egg'])
print(list(map_obj))
>>['bacon', 'toast']

Уменьшать

Давайте познакомимся с последним врагом и, вероятно, с самым сложным из 3. Но не беспокойтесь, это на самом деле довольно просто. Это отношение N к 1, то есть независимо от того, сколько данных мы вливаем в него, мы получим один результат. Это делается путем применения цепочки функций, которые мы собираемся передать. Из трех это единственный, который нам нужно импортировать из функций. В отличие от двух других, его чаще всего можно найти с помощью трех аргументов reduce (some_function, some_collection, some_starting_value), начальное значение необязательно, но обычно рекомендуется указать его. Давайте посмотрим.

from functools import reduce
map_obj = reduce(lambda x,y: x+" loves "+y, ['bacon','toast','egg'],"Everyone")
print(map_obj)
>>'Everyone loves bacon loves toast loves egg'

Как мы видим, нам пришлось использовать лямбда-функцию, которая принимает одновременно два аргумента, а именно x, y. Затем он цепляет их по списку. Давайте представим, как он проходит по списку

  1. x = «Все», y = «бекон»: return «Все любят бекон»
  2. x = «Все любят бекон», y = «тост»: return «Все любят бекон, любят тосты»
  3. x = «Все любят бекон, любят тосты», y = «яйцо»: return «Все любят бекон, любят тосты, любят яйца»

Итак, у нас есть последний элемент: «Все любят бекон, любят тосты, любят яйца». Это основные концепции, позволяющие с большей легкостью перемещаться по конвейеру обработки данных. Следует отметить, что не на каждом языке программирования вы можете предполагать, что функция сокращения будет обрабатывать элемент по порядку, например. на некоторых языках это может быть «Все любят яйца, любят тосты, любят бекон».

Объединить

Чтобы убедиться, что мы поняли концепции, давайте воспользуемся ими вместе и построим более сложный пример.

from functools import reduce
vals = [0,1,2,3,4,5,6,7,8,9]
# Let's add 1 to each element >> [1,2,3,4,5,6,7,8,9,10]
map_obj = map(lambda x: x+1,vals)
# Let's only take the uneven ones >> [1, 3, 5, 7, 9]
map_obj = filter(lambda x: x%2 == 1,map_obj)
# Let's reduce them by summing them up, ((((0+1)+3)+5)+7)+9=25
map_obj = reduce(lambda x,y: x+y,map_obj,0)
print(map_obj)
>> 25

Как мы видим, мы можем создавать довольно мощные вещи, используя комбинацию 3. Давайте перейдем к последнему примеру, чтобы проиллюстрировать, для чего это можно использовать на практике. Для этого мы загружаем небольшое подмножество набора данных и распечатываем города, которые являются столицами и имеют более 10 миллионов жителей!

from functools import reduce
#Let's define some data
data=[['Tokyo', 35676000.0, 'primary'], ['New York', 19354922.0, 'nan'], ['Mexico City', 19028000.0, 'primary'], ['Mumbai', 18978000.0, 'admin'], ['São Paulo', 18845000.0, 'admin'], ['Delhi', 15926000.0, 'admin'], ['Shanghai', 14987000.0, 'admin'], ['Kolkata', 14787000.0, 'admin'], ['Los Angeles', 12815475.0, 'nan'], ['Dhaka', 12797394.0, 'primary'], ['Buenos Aires', 12795000.0, 'primary'], ['Karachi', 12130000.0, 'admin'], ['Cairo', 11893000.0, 'primary'], ['Rio de Janeiro', 11748000.0, 'admin'], ['Ōsaka', 11294000.0, 'admin'], ['Beijing', 11106000.0, 'primary'], ['Manila', 11100000.0, 'primary'], ['Moscow', 10452000.0, 'primary'], ['Istanbul', 10061000.0, 'admin'], ['Paris', 9904000.0, 'primary']]
map_obj = filter(lambda x: x[2]=='primary' and x[1]>10000000,data)
map_obj = map(lambda x: x[0], map_obj)
map_obj = reduce(lambda x,y: x+", "+y, map_obj, 'Cities:')
print(map_obj)
>> Cities:, Tokyo, Mexico City, Dhaka, Buenos Aires, Cairo, Beijing, Manila, Moscow

Если вам понравилась эта статья, я буду рад подключиться к ней в Твиттере или LinkedIn.

Обязательно загляните на мой канал YouTube, где я буду публиковать новые видео каждую неделю.