Memahami fungsi peta

311
map(function, iterable, ...)

Terapkan fungsi ke setiap item yang dapat diubah dan kembalikan daftar hasil. Jika argumen iterable tambahan diteruskan, fungsi harus mengambil banyak argumen dan diterapkan ke item dari semua iterable secara paralel.

Jika satu iterable lebih pendek dari yang lain itu diasumsikan diperpanjang dengan Tidak ada item.

Jika fungsi adalah None, fungsi identitas diasumsikan; jika ada beberapa argumen, map()mengembalikan daftar yang terdiri dari tupel yang berisi item yang sesuai dari semua iterables (semacam operasi transpos).

Argumen iterable dapat berupa urutan atau objek iterable; hasilnya selalu daftar.

Apa peran ini dalam membuat produk Cartesius?

content = map(tuple, array)

Apa efek menempatkan tuple di mana saja di sana? Saya juga memperhatikan bahwa tanpa fungsi peta output abcdan dengannya, itu a, b, c.

Saya ingin sepenuhnya memahami fungsi ini. Definisi referensi juga sulit dimengerti. Bulu yang terlalu mewah.

Master Web
sumber
2
Apa yang sebenarnya ingin Anda capai dan mengapa secara spesifik ingin Anda gunakan map?
Kris Harper
3
@ Webmaster ya, per kalimat pertama dalam dokumentasi yang Anda tempel - "Terapkan fungsi ke setiap item yang dapat diubah". Sisa dari paragraf ini adalah tentang kasus-kasus yang lebih kompleks - seperti yang map(None, a, b, c)ternyata dilakukan zip(a, b, c). Tetapi Anda sangat jarang melihatnya dalam praktik, justru karena zippanggilan itu setara.
lvc
9
Saya berusaha keras untuk belajar python dan setiap kali saya membuka definisi di python.org. setelah kalimat pertama, saya tidak mengerti apa-apa. Baik. Terima kasih.
Master Web
2
tupleadalah fungsi (well, ini lebih bernuansa dari itu, tetapi berperilaku seperti fungsi) yang mengambil iterable, dan memberi Anda tuple dengan elemen yang sama - jadi tuple([1, 2, 3])setara dengan (1, 2, 3). Sebab map(tuple, array), arrayakan menjadi iterable dari iterables (pikirkan daftar daftar), dan itu memberi Anda kembali setiap daftar batin berubah menjadi tuple.
lvc
1
Secara umum, ini adalah kalimat pertama dari dokumentasi fungsi apa pun yang paling penting. Jika Anda mengerti itu, Anda mendapatkan intinya. Sisanya menentukan perilaku rinci, dan beberapa yang akan menjadi buram sedikit untuk memulai dengan, dan Anda mungkin perlu untuk menemukan sebuah idiom aneh berdasarkan itu sebelum Anda melihat "oh, itu apa artinya!". Tapi begitu Anda mendapatkan momen bola lampu untuk beberapa builtin, Anda harus mulai dapat memahami dokumen sedikit lebih mudah.
lvc

Jawaban:

441

maptidak terlalu pythonic. Saya akan merekomendasikan menggunakan daftar pemahaman sebagai gantinya:

map(f, iterable)

pada dasarnya setara dengan:

[f(x) for x in iterable]

mapsendiri tidak dapat melakukan produk Cartesian, karena panjang daftar outputnya selalu sama dengan daftar inputnya. Anda dapat dengan mudah melakukan produk Cartesian dengan pemahaman daftar:

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

Sintaksnya sedikit membingungkan - pada dasarnya setara dengan:

result = []
for a in iterable_a:
    for b in iterable_b:
        result.append((a, b))
dave
sumber
36
Saya menemukan menggunakan mapverbose jauh lebih sedikit daripada daftar pemahaman, setidaknya untuk kasus yang Anda tunjukkan.
marbel
1
Bagaimana cara saya menggunakan peta untuk properti? Apa mappersamaannya [v.__name__ for v in (object, str)]?
A Sz
@ ASz Bagaimana map(lambda v: v.__name__, list)?
Kilian
10
peta lebih cepat karena tidak memanggil fungsi berdasarkan panjang iterator .. fungsi panggilan memiliki overhead .. Tonton 6:00 youtube.com/watch?v=SiXyyOA6RZg&t=813s
anati
1
@anati saya pikir kadangmap - kadang lebih cepat daripada pemahaman, kadang tidak, justru karena fungsi panggilan overhead? Secara khusus, heuristik yang saya pelajari adalah bahwa ketika menggunakan mapmengharuskan Anda untuk memperkenalkan panggilan fungsi tambahan, pemahaman lebih cepat? Misalnya saya dituntun untuk percaya bahwa map(lambda foo: foo.bar, my_list)itu lebih lambat daripada foo.bar for foo in my_list, dan bahkan map(operator.add, my_list_of_pairs)lebih lambat daripada x + y for x, y in my_list_of_pairs, justru karena panggilan fungsi tambahan.
mtraceur
86

mapsama sekali tidak berhubungan dengan produk Cartesian, meskipun saya membayangkan seseorang yang fasih dalam pemrograman fungsional dapat menghasilkan beberapa cara yang mustahil untuk memahami cara menghasilkan yang menggunakan map.

map di Python 3 setara dengan ini:

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

dan satu-satunya perbedaan dalam Python 2 adalah bahwa ia akan membangun daftar lengkap hasil untuk mengembalikan sekaligus, bukan yielding.

Meskipun konvensi Python biasanya lebih suka daftar pemahaman (atau ekspresi generator) untuk mencapai hasil yang sama dengan panggilan map, terutama jika Anda menggunakan ekspresi lambda sebagai argumen pertama:

[func(i) for i in iterable]

Sebagai contoh dari apa yang Anda minta di komentar pada pertanyaan - "mengubah string menjadi array", dengan 'array' Anda mungkin ingin tuple atau daftar (keduanya berperilaku sedikit seperti array dari bahasa lain) -

 >>> 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')

Penggunaan di mapsini adalah jika Anda mulai dengan daftar string alih-alih string tunggal - mapdapat mendaftarkan semuanya secara individual:

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

Catatan yang map(list, a)setara dalam Python 2, tetapi dalam Python 3 Anda perlu listpanggilan jika Anda ingin melakukan apa pun selain memberi makan ke dalam satu forlingkaran (atau fungsi pemrosesan seperti sumitu hanya membutuhkan iterable, dan bukan urutan). Tetapi perhatikan juga bahwa pemahaman daftar biasanya lebih disukai:

>>> [list(b) for b in a]
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]
lvc
sumber
map (fun x -> (x, x)) tampaknya tidak sulit untuk dipahami ... (meskipun mengeluarkan produk kartesius yang benar dari peta tidak mungkin dilakukan, apa pun yang dihasilkan peta selalu berupa daftar)
Kristopher Micinski
36

map membuat daftar baru dengan menerapkan fungsi ke setiap elemen sumber:

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 mapsetara dengan zipping input iterables bersama-sama dan kemudian menerapkan fungsi transformasi pada setiap elemen dari daftar ritsleting menengah. Ini bukan produk Cartesian:

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))

Saya telah menggunakan di zipsini, tetapi mapperilaku sebenarnya sedikit berbeda ketika iterables tidak memiliki ukuran yang sama - seperti dicatat dalam dokumentasinya, ia memperluas iterables untuk mengandung None.

Cat Plus Plus
sumber
1
rumit, mencoba mencerna posting ini
Web Master
1
@ Webmaster Apa rumitnya?
Jossie Calderon
Jawaban terbaik menurut saya. Menggunakan lambda pada contoh sebagai fungsi membuatnya sangat jelas.
sheldonzy
Sayangnya semua ini tidak setara - outputnya [2,4,6]untuk pemahaman daftar dan loop eksplisit, tetapi peta mengembalikan objek peta - misalnya saya mendapatkan ini:<map at 0x123a49978> Yang kemudian harus saya paksa masuk ke dalam daftar.
leerssej
20

Sederhanakan sedikit, Anda dapat membayangkan map()melakukan sesuatu seperti ini:

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

Seperti yang Anda lihat, dibutuhkan fungsi dan daftar, dan mengembalikan daftar baru dengan hasil menerapkan fungsi ke masing-masing elemen dalam daftar input. Saya mengatakan "menyederhanakan sedikit" karena pada kenyataannya map()dapat memproses lebih dari satu iterable:

Jika argumen iterable tambahan diteruskan, fungsi harus mengambil banyak argumen dan diterapkan ke item dari semua iterable secara paralel. Jika satu iterable lebih pendek dari yang lain itu diasumsikan diperpanjang dengan Tidak ada item.

Untuk bagian kedua dalam pertanyaan: Apa peran ini dalam membuat produk Cartesian? baik,map() bisa digunakan untuk menghasilkan produk kartesius dari daftar seperti ini:

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

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

... Tapi jujur ​​saja, menggunakan product()adalah cara yang lebih sederhana dan alami untuk menyelesaikan masalah:

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

Either way, hasilnya adalah produk kartesius lstseperti yang didefinisikan di atas:

[(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)]
Óscar López
sumber
17

Itu map() fungsi yang ada untuk menerapkan prosedur yang sama untuk setiap item dalam struktur data iterable, seperti daftar, generator, string, dan hal-hal lainnya.

Mari kita lihat sebuah contoh: map() dapat mengulangi setiap item dalam daftar dan menerapkan fungsi untuk setiap item, daripada mengembalikan (memberikan Anda kembali) daftar baru.

Bayangkan Anda memiliki fungsi yang mengambil angka, menambahkan 1 ke nomor itu dan mengembalikannya:

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

Anda juga memiliki daftar angka:

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

jika Anda ingin menambah setiap angka dalam daftar, Anda dapat melakukan hal berikut:

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

Catatan: Minimal map() membutuhkan dua argumen. Pertama nama fungsi dan kedua sesuatu seperti daftar.

Mari kita lihat beberapa hal keren lainnya yang map()bisa dilakukan. map()dapat mengambil beberapa iterables (daftar, string, dll.) dan meneruskan elemen dari setiap iterable ke fungsi sebagai argumen.

Kami memiliki tiga daftar:

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

map() dapat membuat Anda daftar baru yang menampung penambahan elemen pada indeks tertentu.

Sekarang ingat map(), butuh fungsi. Kali ini kita akan menggunakan sum()fungsi bawaan . Berlari map()memberikan hasil sebagai berikut:

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

INGAT:
Dalam Python 2 map(), akan iterate (melalui elemen daftar) sesuai dengan daftar terpanjang, dan meneruskan Noneke fungsi untuk daftar pendek, jadi fungsi Anda harus mencari Nonedan menanganinya, jika tidak, Anda akan mendapatkan kesalahan. Dalam Python 3 map()akan berhenti setelah selesai dengan daftar terpendek. Juga, dalam Python 3, map()mengembalikan sebuah iterator, bukan daftar.

BlooB
sumber
8

Python3 - map (func, iterable)

Satu hal yang tidak disebutkan sepenuhnya (walaupun @BlooB menyebutkannya) adalah peta mengembalikan objek peta BUKAN daftar. Ini adalah perbedaan besar ketika datang ke kinerja waktu pada inisialisasi dan iterasi. Pertimbangkan dua tes ini.

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

Seperti yang Anda lihat, menginisialisasi fungsi peta hampir tidak memerlukan waktu sama sekali. Namun iterasi melalui objek peta membutuhkan waktu lebih lama daripada hanya iterasi melalui iterable. Ini berarti bahwa fungsi yang diteruskan ke peta () tidak diterapkan ke setiap elemen hingga elemen tersebut tercapai dalam iterasi. Jika Anda ingin daftar, gunakan daftar pemahaman. Jika Anda berencana untuk mengulanginya dalam for for loop dan akan pecah di beberapa titik, maka gunakan peta.

Ranga
sumber