วิธีการทำข้อโต้แย้งหลายฟังก์ชั่นแผนที่ที่หนึ่งยังคงเหมือนกันในหลาม?


155

ให้บอกว่าเรามีฟังก์ชั่นการเพิ่มดังนี้

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

เราต้องการใช้ฟังก์ชั่นแผนที่สำหรับอาเรย์

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

ซีแมนทิกส์ฉันต้องการเพิ่ม 2 ลงในทุก ๆ องค์ประกอบของอาเรย์ แต่mapฟังก์ชั่นต้องการรายการในอาร์กิวเมนต์ที่สามเช่นกัน

หมายเหตุ:ฉันกำลังเพิ่มตัวอย่างสำหรับความเรียบง่าย ฟังก์ชั่นดั้งเดิมของฉันซับซ้อนกว่ามาก และแน่นอนว่าตัวเลือกของการตั้งค่าเริ่มต้นของyในฟังก์ชั่นการเพิ่มเป็นไปไม่ได้เพราะมันจะเปลี่ยนไปสำหรับการโทรทุกครั้ง


20
นี่เป็นสิ่งเดียวกับใน Lisp: map(add,[1,2,3],[2]*3) โดยทั่วไปmapใช้ในฟังก์ชันเป็นอาร์กิวเมนต์แรกและถ้าฟังก์ชันนี้ใช้อาร์กิวเมนต์Kคุณต้องติดตามด้วยK iterable:addTriple(a,b,c) -> map(addTriple,[...],[...],[...])
watashiSHUN

คำตอบ:


188

ตัวเลือกหนึ่งคือรายการความเข้าใจ:

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

ตัวเลือกเพิ่มเติม:

a = [1, 2, 3]

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

import itertools
map(add, a, itertools.repeat(2, len(a)))

1
มันเร็วแค่ไหนเมื่อเทียบกับฟังก์ชั่นแผนที่?
Shan

@Shan: คล้ายกันมากโดยเฉพาะอย่างยิ่งถ้าadd()เป็นฟังก์ชั่นที่ไม่น่ารำคาญ
Sven Marnach

2
@Shan: ดูที่ NumPy ในกรณีนี้ ถ้านี่เป็นปัญหาสำหรับคุณความแตกต่างของความเร็วระหว่างความเข้าใจในรายการและmap()จะไม่ช่วยอย่างใดอย่างหนึ่ง
Sven Marnach

3
@Shan: ตามที่ฉันพูดไว้ก่อนหน้านี้ให้ดูที่ NumPy มันอาจช่วยเร่งการวนซ้ำอย่างสม่ำเสมอ
Sven Marnach

1
@abarnert: มันไม่ชัดเจนว่า OP ใช้ Python 2 หรือ 3 เพื่อให้แน่ใจว่าตัวอย่างทำงานใน Python 2 ฉันรวมพารามิเตอร์ (โปรดทราบว่าmap()พฤติกรรมเช่นเดียวกับzip_longest()ใน Python 2 ในขณะที่มันทำงานเหมือนzip()ใน Python 3)
Sven Marnach

60

เอกสารแนะนำอย่างชัดเจนว่านี่คือการใช้หลักสำหรับitertools.repeat:

สร้างตัววนซ้ำที่ส่งคืนออบเจ็กต์ซ้ำแล้วซ้ำอีก ทำงานอย่างไม่มีกำหนดเว้นแต่ระบุเวลาโต้แย้ง ใช้เป็นอาร์กิวเมนต์map()สำหรับพารามิเตอร์ที่ไม่แปรเปลี่ยนไปยังฟังก์ชันที่เรียกใช้ ยังใช้กับzip()เพื่อสร้างส่วนที่ไม่เปลี่ยนแปลงของเรคคอร์ด tuple

และไม่มีเหตุผลอะไรที่จะต้องผ่านlen([1,2,3])การtimesโต้แย้ง mapหยุดทันทีที่การทำซ้ำครั้งแรกถูกใช้ไปดังนั้นการทำซ้ำที่ไม่สิ้นสุดจึงเป็นเรื่องที่ดีอย่างสมบูรณ์:

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

อันที่จริงนี่เทียบเท่ากับตัวอย่างสำหรับrepeatในเอกสาร:

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

สิ่งนี้ทำให้เป็นโซลูชันภาษาฟังก์ชั่นขี้เกียจที่สามารถอ่านได้อย่างสมบูรณ์แบบในเงื่อนไข Python-iterator


2
+1 นี่คือคำตอบที่ได้รับการยอมรับ มันขยายไปถึงจำนวนพารามิเตอร์ใด ๆ แน่นอนกับบางรายการคงที่และอื่น ๆ หรือเครื่องกำเนิด เช่น: def f(x,y,z): \\ return '.'.join([x,y,z])แล้ว: ผลตอบแทนlist(map(f, list('abc'), repeat('foo'), list('defgh'))) ['a.foo.d', 'b.foo.e', 'c.foo.f']
Pierre D

5
ใน Python 2 มีความจำเป็นที่จะต้องระบุอาร์กิวเมนต์ความยาวrepeat()เนื่องจากmap()จะทำงานจนกว่าตัววนซ้ำที่ยาวที่สุดจะหมดใน Python เวอร์ชันนั้นซึ่งจะเติมNoneค่าที่หายไปทั้งหมด การพูดว่า "ไม่มีเหตุผล" ที่จะผ่านพารามิเตอร์นั้นผิด
Sven Marnach

ความคิดเห็นของ @SvenMarnach ไม่น้อย: พฤติกรรมของPython 3และPython 2แตกต่างกันอย่างมาก!
Agustín

36

ใช้รายการความเข้าใจ

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

หากคุณจริงๆ , จริงๆ , จริงๆต้องการที่จะใช้mapให้มันฟังก์ชั่นที่ไม่ระบุชื่อเป็นอาร์กิวเมนต์แรก:

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

16

แผนที่สามารถมีหลายอาร์กิวเมนต์วิธีมาตรฐานคือ

map(add, a, b)

ในคำถามของคุณมันควรจะเป็น

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

ไม่แน่ใจว่าคำถามของเขามีความหมายอย่างไร แต่ฉันคิดว่าการเพิ่มยอมรับ 2 ค่าและ 2 นั้นไม่ได้รับการแก้ไขและควรมาจากผู้ใช้เช่น arg1 กำลังจะมา ดังนั้นในกรณีนี้เราจะเรียกเพิ่ม (x, y) ใต้แผนที่ได้อย่างไร?
Bimlesh Sharma

15

คำตอบที่ถูกต้องนั้นง่ายกว่าที่คุณคิด เพียงทำ:

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

และเปลี่ยนการใช้งานของการเพิ่มที่จะใช้สิ่งอันดับ

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

สิ่งนี้สามารถจัดการกรณีการใช้งานที่ซับซ้อนซึ่งทั้งสองพารามิเตอร์เพิ่มเป็นแบบไดนามิก


14

บางครั้งฉันแก้ไขสถานการณ์ที่คล้ายกัน (เช่นการใช้วิธีการpandas.apply ) โดยใช้การปิด

ในการใช้งานคุณกำหนดฟังก์ชั่นที่กำหนดและส่งคืน wrapper สำหรับฟังก์ชั่นของคุณทำให้พารามิเตอร์อย่างใดอย่างหนึ่งเป็นค่าคงที่

บางสิ่งเช่นนี้

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

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

จากนั้นadd_constant(y)ส่งคืนฟังก์ชันซึ่งสามารถใช้เพื่อเพิ่มyให้กับค่าที่กำหนด:

>>> add_constant(2)(3)
5

ซึ่งช่วยให้คุณสามารถใช้งานได้ในทุกสถานการณ์ที่พารามิเตอร์ได้รับครั้งละหนึ่งพารามิเตอร์:

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

แก้ไข

หากคุณไม่ต้องการเขียนฟังก์ชันการปิดที่อื่นคุณมีความเป็นไปได้ที่จะสร้างมันขึ้นมาทันทีโดยใช้ฟังก์ชั่นแลมบ์ดา:

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

13

หากคุณมีให้ฉันจะพิจารณาใช้ numpy มันเร็วมากสำหรับการดำเนินการประเภทนี้:

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

นี่คือการสมมติว่าแอปพลิเคชันที่แท้จริงของคุณกำลังทำการดำเนินการทางคณิตศาสตร์


10

หากคุณจำเป็นต้องใช้ฟังก์ชั่นแผนที่จริงๆ (เช่นการมอบหมายชั้นเรียนของฉันที่นี่ ... ) คุณสามารถใช้ฟังก์ชั่น wrapper กับ 1 อาร์กิวเมนต์ผ่านส่วนที่เหลือไปยังต้นฉบับในร่างกายของมัน เช่น:

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


map(myFunc, itterable)

สกปรกและน่าเกลียด


1
ฉันคิดว่านี่เป็นการปิดบางอย่างและเพิ่มอีกอย่าง คล้ายกับฟังก์ชั่นบางส่วนตามคำตอบที่ยอมรับได้
Aaron Hall

1
myFuncต้องการreturn Func(arg, extraArguments)
PM 2Ring

ฉันยืนแก้ไข @ PM2Ring ได้จริง อัปเดตรหัส
Todor Minakov

Func ถูกกำหนดไว้ที่ไหน? เพราะฉันได้รับข้อผิดพลาดของชื่อสำหรับ Func
Nikhil Mishra

Funcเป็นชื่อของฟังก์ชั่นดั้งเดิมของคุณ - สำหรับ OP คับจะเป็นaddตัวอย่าง
Todor Minakov

6

ฉันเชื่อว่า starmap คือสิ่งที่คุณต้องการ:

from itertools import starmap


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

list(starmap(test, [(1, 2, 3), (4, 5, 6)]))

คำสะกดผิดในตัวอย่างของคุณ: list (starmap (ทดสอบ, [(1, 2, 3), (4, 5, 6)])))
Teebu

โอ้ใช่. ขอบคุณ :)
Shqi.Yang

1

เพื่อส่งอาร์กิวเมนต์จำนวนมากไปยังmapฟังก์ชัน

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

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

นี่qคือฟังก์ชั่นที่มีหลายอาร์กิวเมนต์ที่map ()โทร ตรวจสอบให้แน่ใจความยาวของทั้งสองช่วงคือ

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

1

ใน:nums = [1, 2, 3]

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

ออก:[3, 4, 5]


1
สิ่งนี้ไม่ได้ให้คำตอบสำหรับคำถาม คุณสามารถค้นหาคำถามที่คล้ายกันหรืออ้างอิงคำถามที่เกี่ยวข้องและเชื่อมโยงทางด้านขวาของหน้าเพื่อค้นหาคำตอบ หากคุณมีคำถามที่เกี่ยวข้อง แต่แตกต่างกันให้ถามคำถามใหม่และรวมลิงก์ไปยังคำถามนี้เพื่อช่วยจัดเตรียมบริบท ดู: ถามคำถามรับคำตอบไม่มีสิ่งรบกวน
ทิม Diekmann


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

โดยการตัดการเรียกฟังก์ชันด้วยแลมบ์ดาและการใช้การแกะดาวคุณสามารถทำแผนที่ด้วยจำนวนอาร์กิวเมนต์โดยอำเภอใจ


แลมบ์ดาช้ามากให้ใช้ functools แทน
Wang

0

ตัวเลือกอื่นคือ:

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

รูปแบบนี้มีประโยชน์มากเมื่อเรียกใช้หลายฟังก์ชัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.