Bagaimana cara melakukan beberapa argumen untuk memetakan fungsi di mana satu tetap sama dengan python?

155

Katakanlah kita memiliki fungsi add sebagai berikut

def add(x, y):
    return x + y

kami ingin menerapkan fungsi peta untuk sebuah array

map(add, [1, 2, 3], 2)

Semantiknya adalah saya ingin menambahkan 2 ke setiap elemen array. Tetapi mapfungsinya membutuhkan daftar pada argumen ketiga juga.

Catatan: Saya menempatkan contoh tambahkan untuk kesederhanaan. Fungsi asli saya jauh lebih rumit. Dan tentu saja opsi pengaturan nilai default ydalam fungsi add tidak dipertanyakan karena akan diubah untuk setiap panggilan.

Shan
sumber
20
ini persis sama dengan di Lisp: map(add,[1,2,3],[2]*3) secara umum mapmengambil fungsi sebagai argumen pertama, dan jika fungsi ini mengambil argumen K , Anda harus menindaklanjuti dengan K iterable:addTriple(a,b,c) -> map(addTriple,[...],[...],[...])
watashiSHUN

Jawaban:

188

Salah satu opsi adalah pemahaman daftar:

[add(x, 2) for x in [1, 2, 3]]

Lebih banyak pilihan:

a = [1, 2, 3]

import functools
map(functools.partial(add, y=2), a)

import itertools
map(add, a, itertools.repeat(2, len(a)))
Sven Marnach
sumber
1
ya, tapi seberapa cepat dibandingkan dengan fungsi peta?
Shan
@ Shan: Sangat mirip, terutama jika add()fungsi non-sepele
Sven Marnach
2
@ Shan: Lihatlah NumPy dalam hal ini. Jika ini benar-benar masalah bagi Anda, perbedaan kecepatan antara pemahaman daftar dan map()tidak akan membantu.
Sven Marnach
3
@ Shan: Seperti yang saya katakan sebelumnya, lihat NumPy. Ini mungkin membantu mempercepat loop secara conderable, asalkan mereka dapat di-vectorised.
Sven Marnach
1
@abarnert: Tidak jelas apakah OP menggunakan Python 2 atau 3. Untuk memastikan contoh bekerja di Python 2, saya menyertakan parameter. (Perhatikan bahwa map()berperilaku seperti zip_longest()di Python 2, sementara itu berperilaku seperti zip()di Python 3.)
Sven Marnach
60

Dokumen secara eksplisit menyarankan ini adalah penggunaan utama untuk itertools.repeat:

Buat iterator yang mengembalikan objek berulang-ulang. Berjalan tanpa batas waktu kecuali argumen kali ditentukan. Digunakan sebagai argumen map()untuk parameter invarian untuk fungsi yang dipanggil. Juga digunakan dengan zip()untuk membuat bagian invarian dari catatan tuple.

Dan tidak ada alasan untuk lulus len([1,2,3])sebagai timesargumen; mapberhenti segera setelah iterable pertama dikonsumsi, sehingga iterable tak terbatas baik-baik saja:

>>> from operator import add
>>> from itertools import repeat
>>> list(map(add, [1,2,3], repeat(4)))
[5, 6, 7]

Bahkan, ini setara dengan contoh repeatdalam dokumen:

>>> list(map(pow, range(10), repeat(2)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Ini membuat solusi malas-fungsional-bahasa-y yang bagus yang juga dapat dibaca dengan sempurna dalam istilah Python-iterator.

abarnert
sumber
2
+1 Ini harus menjadi jawaban yang diterima. Itu meluas ke sejumlah parameter, tentu saja, dengan beberapa konstan atau daftar atau generator. Misalnya: def f(x,y,z): \\ return '.'.join([x,y,z])lalu: list(map(f, list('abc'), repeat('foo'), list('defgh')))kembali ['a.foo.d', 'b.foo.e', 'c.foo.f'].
Pierre D
5
Dalam Python 2, perlu untuk memberikan argumen panjang repeat(), karena map()akan berjalan sampai iterator terpanjang habis dalam versi Python itu, mengisi Nonesemua nilai yang hilang. Mengatakan bahwa "tidak ada alasan" untuk melewatkan parameter salah.
Sven Marnach
Komentar @SvenMarnach tidak kecil: Perilaku Python 3 dan Python 2 bervariasi secara drastis!
Agustín
36

Gunakan pemahaman daftar.

[x + 2 for x in [1, 2, 3]]

Jika Anda benar-benar , benar-benar , benar-benar ingin menggunakan map, memberikan fungsi anonim sebagai argumen pertama:

map(lambda x: x + 2, [1,2,3])
Fred Foo
sumber
16

Peta dapat berisi banyak argumen, cara standarnya adalah

map(add, a, b)

Dalam pertanyaan Anda, seharusnya

map(add, a, [2]*len(a))
Yi.ding
sumber
Tidak yakin apa maksud pertanyaannya tetapi saya pikir menambahkan menerima 2 nilai dan 2 itu tidak diperbaiki dan harus datang dari pengguna seperti arg1 akan datang. jadi dalam hal ini bagaimana kita harus memanggil add (x, y) di bawah peta?
Bimlesh Sharma
15

Jawaban yang benar lebih sederhana dari yang Anda pikirkan. Cukup lakukan:

map(add, [(x, 2) for x in [1,2,3]])

Dan mengubah implementasi add untuk mengambil tuple yaitu

def add(t):
   x, y = t
   return x+y

Ini dapat menangani setiap kasus penggunaan yang rumit di mana kedua parameter add bersifat dinamis.

Simon Ndunda
sumber
14

Kadang-kadang saya menyelesaikan situasi serupa (seperti menggunakan metode pandas. Apply ) menggunakan penutupan

Untuk menggunakannya, Anda mendefinisikan fungsi yang secara dinamis mendefinisikan dan mengembalikan pembungkus untuk fungsi Anda, secara efektif membuat salah satu parameter menjadi konstan.

Sesuatu seperti ini:

def add(x, y):
   return x + y

def add_constant(y):
    def f(x):
        return add(x, y)
    return f

Lalu, add_constant(y)kembalikan fungsi yang bisa digunakan untuk menambah ynilai apa pun yang diberikan:

>>> add_constant(2)(3)
5

Yang memungkinkan Anda untuk menggunakannya dalam situasi apa pun di mana parameter diberikan satu per satu:

>>> map(add_constant(2), [1,2,3])
[3, 4, 5]

sunting

Jika Anda tidak ingin harus menulis fungsi penutupan di tempat lain, Anda selalu memiliki kemungkinan untuk membuatnya dengan menggunakan fungsi lambda:

>>> map(lambda x: add(x, 2), [1, 2, 3])
[3, 4, 5]
Carles Sala
sumber
13

Jika Anda memilikinya tersedia, saya akan mempertimbangkan menggunakan numpy. Ini sangat cepat untuk jenis operasi ini:

>>> import numpy
>>> numpy.array([1,2,3]) + 2
array([3, 4, 5])

Ini dengan asumsi aplikasi nyata Anda melakukan operasi matematika (yang dapat di-vektor).

jterrace
sumber
10

Jika Anda benar-benar perlu menggunakan fungsi peta (seperti tugas kelas saya di sini ...), Anda dapat menggunakan fungsi wrapper dengan 1 argumen, meneruskan sisanya ke yang asli di tubuhnya; yaitu:

extraArguments = value
def myFunc(arg):
    # call the target function
    return Func(arg, extraArguments)


map(myFunc, itterable)

Kotor & jelek, masih melakukan trik

Todor Minakov
sumber
1
Penutupan, saya pikir ini menambahkan sesuatu, ditambah satu. Mirip dengan fungsi parsial, seperti jawaban yang diterima.
Aaron Hall
1
myFuncperlureturn Func(arg, extraArguments)
PM 2Ring
Saya berdiri dikoreksi @ PM2Ring, itu benar; memperbarui kode.
Todor Minakov
di mana fungsi didefinisikan? karena saya mendapatkan kesalahan nama untuk Func
Nikhil Mishra
Funcadalah nama fungsi asli Anda - untuk OP ketat addmisalnya
Todor Minakov
6

Saya percaya starmap adalah yang Anda butuhkan:

from itertools import starmap


def test(x, y, z):
    return x + y + z

list(starmap(test, [(1, 2, 3), (4, 5, 6)]))
Shqi.Yang
sumber
salah ketik dalam contoh Anda: list (starmap (test, [(1, 2, 3), (4, 5, 6)]))
Teebu
Oh ya. Terima kasih :)
Shqi.Yang
1

Untuk meneruskan beberapa argumen ke suatu mapfungsi.

def q(x,y):
    return x*y

print map (q,range(0,10),range(10,20))

Di sini q adalah fungsi dengan beberapa argumen yang memetakan () panggilan. Pastikan, panjang kedua rentang yaitu

len (range(a,a')) and len (range(b,b')) are equal.
SeasonalShot
sumber
1

Anda dapat memasukkan lambda bersama dengan peta:

list(map(lambda a: a+2, [1, 2, 3]))
Hanish Madan
sumber
1
def func(a, b, c, d):
 return a + b * c % d
map(lambda x: func(*x), [[1,2,3,4], [5,6,7,8]])

Dengan membungkus panggilan fungsi dengan lambda dan menggunakan membongkar bintang, Anda dapat melakukan peta dengan sejumlah argumen sewenang-wenang.

Yuukio
sumber
lambda sangat lambat, gunakan functools sebagai gantinya
Wang
0

Pilihan lain adalah:

results = []
for x in [1,2,3]:
    z = add(x,2)
    ...
    results += [f(z,x,y)]

Format ini sangat berguna saat memanggil beberapa fungsi.

sudoman
sumber