Розуміння функції карти


311
map(function, iterable, ...)

Застосувати функцію до кожного елемента, який можна повторити, і повернути список результатів. Якщо передаються додаткові ітерабельні аргументи, функція повинна брати стільки аргументів і паралельно застосовуватись до елементів з усіх ітерабелів.

Якщо один ітерабельний файл коротший за інший, його передбачається розширити з пунктами None.

Якщо функція є None, передбачається функція ідентичності; якщо є декілька аргументів, map()повертає список, що складається з кортежів, що містять відповідні елементи з усіх ітерабелів (вид операції транспонування).

Ітерабельні аргументи можуть бути послідовністю або будь-яким ітерабельним об'єктом; результат - це завжди список.

Яку роль відіграє декартовий продукт?

content = map(tuple, array)

Який ефект має розміщення кортежу в будь-якому місці? Я також помітив, що без функції карти вихід є, abcа з ним - це a, b, c.

Я хочу повністю зрозуміти цю функцію. Довідкові визначення також важко зрозуміти. Занадто багато фантазійного пуху.


2
Чого ти насправді хочеш досягти і чому конкретно хочеш використовувати map?
Кріс Харпер

3
@WebMaster так, на перше речення в документації, яку ви вставили, - "Застосувати функцію до кожного елемента, який можна повторити". У решті параграфа йдеться про більш складні випадки - начебто map(None, a, b, c)це робиться zip(a, b, c). Але ви дуже рідко це бачите на практиці саме тому, що zipдзвінок рівноцінний.
lvc

9
Я дуже намагаюся вивчити python і кожного разу, коли я відкриваю визначення на python.org. після першого речення я нічого не розумію. Добре. Дякую тобі.
Веб-майстер

2
tupleце функція (ну, її більш нюансована, ніж ця, але вона поводиться як функція), яка бере ітерабельний і дає вам кортеж з тими ж елементами - так tuple([1, 2, 3])це рівнозначно (1, 2, 3). Для map(tuple, array), arrayбуло б итерацией з ітеріруемих (думає , список списків), і це дає вам назад кожен внутрішній список перетворений в кортеж.
lvc

1
Загалом, це найважливіше перше речення документації будь-якої функції. Якщо ви це розумієте, ви отримуєте суть цього. У решті він детально визначає поведінку, і дещо з цього буде трохи непрозорим для початку, і вам, можливо, доведеться натрапити на дивну ідіому, засновану на ній, перш ніж побачите "о, це що означає!". Але як тільки ви отримаєте цей момент лампочки для кількох вбудованих, ви повинні почати мати можливість зрозуміти документи трохи легше.
lvc

Відповіді:


441

mapне особливо пітонічний. Я б рекомендував використовувати замість цього списку:

map(f, iterable)

в основному еквівалентний:

[f(x) for x in iterable]

mapсамостійно не може робити декартовий продукт, оскільки довжина його списку вихідних даних завжди така ж, як і його вхідний список. Ви можете банально зробити декартовий продукт із розумінням списку:

[(a, b) for a in iterable_a for b in iterable_b]

Синтаксис трохи заплутаний - це в основному еквівалентно:

result = []
for a in iterable_a:
    for b in iterable_b:
        result.append((a, b))

36
Я вважаю, що використовую mapнабагато менш багатослівний, ніж перелічення списків, принаймні для випадку, який ви демонструєте.
Марбель

1
Як використовувати карту для властивостей? Що таке map-еквівалент [v.__name__ for v in (object, str)]?
A Sz

@ASz Як щодо map(lambda v: v.__name__, list)?
Кіліан

10
карта швидша, оскільки вона не викликає функції на основі довжини ітераторів .. Функції виклику мають накладні витрати. Дивитися 6:00 youtube.com/watch?v=SiXyyOA6RZg&t=813s
anati

1
@anati я думав , mapбуло іноді швидше , ніж осягнення, іноді немає, саме з - за функції накладних витрат виклику? Зокрема, евристичний, який я дізнався, полягає в тому, що при використанні mapвимагає ввести додатковий виклик функції, розуміння швидше? Наприклад, мене припустили, що map(lambda foo: foo.bar, my_list)це повільніше foo.bar for foo in my_list, а це навіть map(operator.add, my_list_of_pairs)повільніше x + y for x, y in my_list_of_pairs, саме через додатковий виклик функції.
mtraceur

86

mapвзагалі не стосується декартового продукту, хоча я думаю, що хтось добре розбирається у функціональному програмуванні може придумати якийсь неможливий для розуміння спосіб створення виробу за допомогою map.

map в Python 3 рівнозначно цьому:

def map(func, iterable):
    for i in iterable:
        yield func(i)

і єдиною відмінністю в Python 2 є те, що він створить повний список результатів, щоб повернути всі відразу, а не yielding.

Хоча конвенція Python зазвичай віддає перевагу розумінням списку (або генераторним виразам), щоб досягти такого ж результату, як і виклик map, особливо якщо ви використовуєте лямбда-вираз у якості першого аргументу:

[func(i) for i in iterable]

Як приклад того, що ви попросили в коментарях до питання - "перетворити рядок у масив", "масив" ви, мабуть, хочете або кортеж, або список (обидва вони поводяться трохи схожі на масиви з інших мов) -

 >>> a = "hello, world"
 >>> list(a)
['h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd']
>>> tuple(a)
('h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd')

Використання mapтут було б, якщо ви почнете зі списку рядків замість однієї струни - mapможете викласти їх усі окремо:

>>> a = ["foo", "bar", "baz"]
>>> list(map(list, a))
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]

Зауважте, що map(list, a)в Python 2 еквівалентно, але в Python 3 вам потрібен listвиклик, якщо ви хочете зробити що-небудь, крім введення його в forцикл (або функцію обробки такої, sumяка потребує лише ітерабельного, а не послідовності). Але також зауважте ще раз, що зазвичай бажано розуміння списку:

>>> [list(b) for b in a]
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]

карта (весело x -> (x, x)) не здається важкою для розуміння ... (хоча вивести справжній декартовий продукт з карти було б неможливо, все, що створює карта, завжди є якоюсь формою списку)
Крістофер Мічінський

36

map створює новий список, застосовуючи функцію до кожного елемента джерела:

xs = [1, 2, 3]

# all of those are equivalent — the output is [2, 4, 6]
# 1. map
ys = map(lambda x: x * 2, xs)
# 2. list comprehension
ys = [x * 2 for x in xs]
# 3. explicit loop
ys = []
for x in xs:
    ys.append(x * 2)

n-ary mapеквівалентний поєднанню вхідних ітерабелів введення разом, а потім застосуванню функції перетворення на кожному елементі цього проміжного зіпсованого списку. Це не декартовий продукт:

xs = [1, 2, 3]
ys = [2, 4, 6]

def f(x, y):
    return (x * 2, y // 2)

# output: [(2, 1), (4, 2), (6, 3)]
# 1. map
zs = map(f, xs, ys)
# 2. list comp
zs = [f(x, y) for x, y in zip(xs, ys)]
# 3. explicit loop
zs = []
for x, y in zip(xs, ys):
    zs.append(f(x, y))

Я використовував zipтут, але mapповедінка насправді дещо відрізняється, коли ітерабери не однакового розміру - як зазначено в його документації, вона розширює вміст ітерабелів None.


1
складно, намагаючись переварити цю посаду
Веб-майстер

1
@WebMaster Що складного в цьому?
Джоссі Кальдерон

Найкраща відповідь на мій погляд. Використання лямбда в прикладі як функції робить це дуже зрозумілим.
sheldonzy

На жаль, все це не еквівалентно - вихід призначений [2,4,6]для розуміння списку та явних циклів, але карта повертає об’єкт карти - наприклад, я отримую це: <map at 0x123a49978>Я потім повинен примусити до списку.
leerssej

20

Трохи спростивши, ви можете уявити собі map()щось подібне:

def mymap(func, lst):
    result = []
    for e in lst:
        result.append(func(e))
    return result

Як бачите, він приймає функцію та список та повертає новий список із результатом застосування функції до кожного з елементів вхідного списку. Я сказав "трохи спрощуючи", оскільки насправді map()може обробити більше одного ітерабельного:

Якщо передаються додаткові ітерабельні аргументи, функція повинна брати стільки аргументів і паралельно застосовуватись до елементів з усіх ітерабелів. Якщо один ітерабельний файл коротший за інший, його передбачається розширити з пунктами None.

Щодо другої частини запитання: Яку роль відіграє декартовий продукт? добре, map() може бути використаний для створення декартового продукту такого списку:

lst = [1, 2, 3, 4, 5]

from operator import add
reduce(add, map(lambda i: map(lambda j: (i, j), lst), lst))

... Але якщо говорити правду, використання product()набагато більш простого і природного способу вирішення проблеми:

from itertools import product
list(product(lst, lst))

Так чи інакше, результатом є декартовий продукт, lstяк визначено вище:

[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5),
 (2, 1), (2, 2), (2, 3), (2, 4), (2, 5),
 (3, 1), (3, 2), (3, 3), (3, 4), (3, 5),
 (4, 1), (4, 2), (4, 3), (4, 4), (4, 5),
 (5, 1), (5, 2), (5, 3), (5, 4), (5, 5)]

17

map()Функція є , щоб застосувати ту ж процедуру для кожного елемента в Iterable структури даних, як списки, генератори, рядки і інші речі.

Давайте подивимось на приклад: чи map()можна повторити кожен елемент у списку та застосувати функцію до кожного елемента, ніж він поверне (поверне) новий список.

Уявіть, що у вас є функція, яка приймає число, додає 1 до цього числа і повертає його:

def add_one(num):
  new_num = num + 1
  return new_num

Також у вас є список номерів:

my_list = [1, 3, 6, 7, 8, 10]

якщо ви хочете збільшувати кожне число у списку, ви можете зробити наступне:

>>> map(add_one, my_list)
[2, 4, 7, 8, 9, 11]

Примітка: як мінімум map()потрібно два аргументи. Спочатку ім'я функції та друге щось на зразок списку.

Подивимося, які ще круті речі map()можуть зробити. map()може приймати кілька ітерабелів (списки, рядки тощо) і передавати елемент з кожного ітерабету функції як аргумент.

У нас є три списки:

list_one = [1, 2, 3, 4, 5]
list_two = [11, 12, 13, 14, 15]
list_three = [21, 22, 23, 24, 25]

map() може скласти вам новий список, який містить додавання елементів у певний індекс.

Тепер пам’ятайте map(), потрібна функція. На цей раз ми використаємо вбудовану sum()функцію. Біг map()дає такий результат:

>>> map(sum, list_one, list_two, list_three)
[33, 36, 39, 42, 45]

ПАМ’ЯТАЙТЕ:
У Python 2 map()відбудеться ітерація (пройде через елементи списків) відповідно до найдовшого списку та перейде Noneдо функції для коротших списків, тому ваша функція повинна шукати Noneта обробляти їх, інакше ви отримаєте помилки. На Python 3 map()зупиняться після закінчення найкоротшого списку. Також у Python 3 map()повертає ітератор, а не список.


8

Python3 - карта (func, ітерабельна)

Одне, що не згадувалося повністю (хоча @BlooB свого роду це згадувало), це те, що карта повертає об’єкт карти НЕ список. Це велика різниця, коли мова йде про ефективність часу щодо ініціалізації та ітерації. Розглянемо ці два тести.

import time
def test1(iterable):
    a = time.clock()
    map(str, iterable)
    a = time.clock() - a

    b = time.clock()
    [ str(x) for x in iterable ]
    b = time.clock() - b

    print(a,b)


def test2(iterable):
    a = time.clock()
    [ x for x in map(str, iterable)]
    a = time.clock() - a

    b = time.clock()
    [ str(x) for x in iterable ]
    b = time.clock() - b

    print(a,b)


test1(range(2000000))  # Prints ~1.7e-5s   ~8s
test2(range(2000000))  # Prints ~9s        ~8s

Як ви бачите, ініціалізація функції карти зовсім не займає часу. Однак ітерація через об’єкт карти займає більше часу, ніж просто повторення через ітерабельний. Це означає, що функція, передана map (), не застосовується до кожного елемента, поки елемент не буде досягнуто в ітерації. Якщо ви хочете зі списком, використовуйте розуміння списку. Якщо ви плануєте перебрати цикл for для циклу, який прорветься в якийсь момент, використовуйте карту

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.