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.


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

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.


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

16

Peta dapat berisi banyak argumen, cara standarnya adalah

map(add, a, b)

Dalam pertanyaan Anda, seharusnya

map(add, a, [2]*len(a))

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.


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]

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


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


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

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.

1

Di :nums = [1, 2, 3]

Di :map(add, nums, [2]*len(nums))

Di luar:[3, 4, 5]


1
Ini tidak memberikan jawaban untuk pertanyaan itu. Anda dapat mencari pertanyaan serupa , atau merujuk ke pertanyaan terkait dan tertaut di sisi kanan halaman untuk menemukan jawaban. Jika Anda memiliki pertanyaan terkait tetapi berbeda, ajukan pertanyaan baru , dan sertakan tautan ke yang ini untuk membantu memberikan konteks. Lihat: Ajukan pertanyaan, dapatkan jawaban, tanpa gangguan
Tim Diekmann

1

Anda dapat memasukkan lambda bersama dengan peta:

list(map(lambda a: a+2, [1, 2, 3]))

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.


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.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.