ใช้แผนที่หลามและเครื่องมือการทำงานอื่น ๆ


127

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

foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3]

def maptest(foo, bar):
    print foo, bar

map(maptest, foos, bars)

ผลิต:

1.0 1
2.0 2
3.0 3
4.0 None
5.0 None

ถามมีวิธีใช้แผนที่หรือเครื่องมือการทำงานอื่น ๆ ใน python เพื่อสร้างสิ่งต่อไปนี้โดยไม่ต้องวนซ้ำเป็นต้น

1.0 [1,2,3]
2.0 [1,2,3]
3.0 [1,2,3]
4.0 [1,2,3]
5.0 [1,2,3]

เช่นเดียวกับข้อสังเกตว่าการใช้งานจะเปลี่ยนไปอย่างไรหากมีการพึ่งพาระหว่าง foo และ bar เช่น

foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3,4,5]

และพิมพ์:

1.0 [2,3,4,5]
2.0 [1,3,4,5]
3.0 [1,2,4,5]
...

PS: ฉันรู้วิธีทำอย่างไร้เดียงสาโดยใช้ if, ลูปและ / หรือเครื่องกำเนิดไฟฟ้า แต่ฉันต้องการเรียนรู้วิธีบรรลุสิ่งเดียวกันโดยใช้เครื่องมือที่ใช้งานได้ เป็นเพียงกรณีของการเพิ่มคำสั่ง if ลงใน maptest หรือใช้แผนที่ตัวกรองอื่นกับแถบภายในภายใน maptest หรือไม่?


ขอบคุณเพื่อน. ฉันต้องยอมรับว่าฉันพยายามเรียนรู้แนวคิดของการเขียนโปรแกรมเชิงฟังก์ชันผ่าน python

1
บทช่วยสอนที่ดีสำหรับที่นี่: dreamsyssoft.com/python-scripting-tutorial/…
Rocky Pulley

คำตอบ:


54

วิธีที่ง่ายที่สุดคือไม่ต้องbarsผ่านฟังก์ชั่นต่างๆ แต่เข้าถึงได้โดยตรงจากmaptest:

foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3]

def maptest(foo):
    print foo, bars

map(maptest, foos)

ด้วยmaptestฟังก์ชันดั้งเดิมของคุณคุณสามารถใช้ฟังก์ชันแลมด้าในmap:

map((lambda foo: maptest(foo, bars)), foos)

สิ่งที่ไม่ดีเมื่อบาร์มาจากรายการ
Phyo Arkar Lwin

59
โซลูชันนี้ขัดต่อหลักการของการเขียนโปรแกรมเชิงฟังก์ชันซึ่ง OP ต้องการเรียนรู้โดยตรง กฎพื้นฐานในการเขียนโปรแกรมเชิงฟังก์ชันคือทุกครั้งที่คุณเรียกใช้ฟังก์ชันด้วยอาร์กิวเมนต์เดียวกันคุณจะได้รับผลลัพธ์เดียวกันเสมอ วิธีนี้จะหลีกเลี่ยงรังของแมลงงูพิษที่เกิดจากการมีสถานะระดับโลก เนื่องจาก maptest ขึ้นอยู่กับความหมายภายนอกของแท่งหลักการนี้จึงเสียไป
image_doctor

3
เรียน Stack overflow เนื่องจากคุณต้องการปิดคำถามและค่อนข้างหนักหน่วงทำไมคุณไม่ทำเครื่องหมายคำถามนี้เป็นคำตอบและทำเครื่องหมายคำตอบที่ถูกต้องเป็นคำตอบ ขอแสดงความนับถือเรา
Bahadir Cambel

1
@image_doctor ใน FP มันก็โอเคที่จะเข้าถึงค่าคงที่ทั่วโลก (ถือว่าเป็นค่า nullary fuction)
Peter K

1
@BahadirCambel การกลั่นกรอง Stack Overflow อาจเป็นงานหนักในบางครั้ง แต่เครื่องหมายถูกมักจะเป็นของ OP เสมอ
wizzwizz4

194

คุณคุ้นเคยกับภาษาที่ใช้งานได้อื่น ๆ หรือไม่? เช่นคุณกำลังพยายามเรียนรู้ว่า python ทำการเขียนโปรแกรมเชิงฟังก์ชันอย่างไรหรือคุณกำลังพยายามเรียนรู้เกี่ยวกับการเขียนโปรแกรมเชิงฟังก์ชันและการใช้ python เป็นยานพาหนะ

นอกจากนี้คุณเข้าใจความเข้าใจในรายการหรือไม่

map(f, sequence)

เทียบเท่าโดยตรง (*) กับ:

[f(x) for x in sequence]

อันที่จริงฉันคิดว่าmap()ครั้งหนึ่งเคยถูกกำหนดให้ลบออกจาก python 3.0 เนื่องจากซ้ำซ้อน (ซึ่งไม่ได้เกิดขึ้น)

map(f, sequence1, sequence2)

ส่วนใหญ่เทียบเท่ากับ:

[f(x1, x2) for x1, x2 in zip(sequence1, sequence2)]

(มีความแตกต่างในวิธีจัดการกรณีที่ลำดับมีความยาวต่างกันอย่างที่คุณเห็นให้map()เติม None เมื่อลำดับใดลำดับหนึ่งหมดลงในขณะที่zip()หยุดเมื่อลำดับที่สั้นที่สุดหยุดลง)

ดังนั้นเพื่อตอบคำถามเฉพาะของคุณคุณกำลังพยายามสร้างผลลัพธ์:

foos[0], bars
foos[1], bars
foos[2], bars
# etc.

คุณสามารถทำได้โดยการเขียนฟังก์ชันที่รับอาร์กิวเมนต์เดียวแล้วพิมพ์ตามด้วยแถบ:

def maptest(x):
     print x, bars
map(maptest, foos)

หรือคุณสามารถสร้างรายการที่มีลักษณะดังนี้:

[bars, bars, bars, ] # etc.

และใช้ maptest เดิมของคุณ:

def maptest(x, y):
    print x, y

วิธีหนึ่งในการทำเช่นนี้คือการสร้างรายการล่วงหน้าอย่างชัดเจน:

barses = [bars] * len(foos)
map(maptest, foos, barses)

หรือคุณสามารถดึงitertoolsโมดูลเข้ามา itertoolsมีฟังก์ชันที่ชาญฉลาดมากมายที่ช่วยให้คุณเขียนโปรแกรมการประเมินผลแบบขี้เกียจในรูปแบบฟังก์ชันใน python ในกรณีนี้เราต้องการitertools.repeatซึ่งจะส่งออกอาร์กิวเมนต์ไปเรื่อย ๆ เมื่อคุณทำซ้ำ ข้อเท็จจริงสุดท้ายนี้หมายความว่าหากคุณทำ:

map(maptest, foos, itertools.repeat(bars))

คุณจะได้รับผลลัพธ์ที่ไม่มีที่สิ้นสุดเนื่องจากmap()ยังคงดำเนินต่อไปตราบเท่าที่หนึ่งในอาร์กิวเมนต์ยังคงให้ผลลัพธ์ อย่างไรก็ตามitertools.imapก็เหมือนกับmap()แต่จะหยุดทันทีที่หยุดทำซ้ำได้สั้นที่สุด

itertools.imap(maptest, foos, itertools.repeat(bars))

หวังว่านี่จะช่วยได้ :-)

(*) มันแตกต่างกันเล็กน้อยใน python 3.0 ที่นั่น map () ส่งคืนนิพจน์ตัวสร้างเป็นหลัก


ดังนั้นฉันเข้าใจถูกต้องหรือไม่ว่าต่างจากแผนที่itertools.imap(f, sequence1, sequence2)จริง ๆ แล้วเทียบเท่ากับ[f(x1, x2) for x1, x2 in zip(sequence1, sequence2)]?
Jon Coombs

การทดสอบเล็กน้อยฉันเห็นว่ามันส่งคืนอ็อบเจ็กต์ itertools.imap ดังนั้นบางทีนี่อาจจะ 'เทียบเท่า' มากกว่า:list(itertools.imap(f, sequence1, sequence2))
Jon Coombs

นี่ควรเป็นคำตอบที่ได้รับอนุมัติ
Rob Grant

30

นี่คือทางออกที่คุณกำลังมองหา:

>>> foos = [1.0, 2.0, 3.0, 4.0, 5.0]
>>> bars = [1, 2, 3]
>>> [(x, bars) for x in foos]
[(1.0, [1, 2, 3]), (2.0, [1, 2, 3]), (3.0, [1, 2, 3]), (4.0, [1, 2, 3]), (5.0, [
1, 2, 3])]

ฉันขอแนะนำให้ใช้การทำความเข้าใจรายการ ( [(x, bars) for x in foos]ส่วน) มากกว่าการใช้แผนที่เนื่องจากหลีกเลี่ยงค่าใช้จ่ายของการเรียกใช้ฟังก์ชันในการทำซ้ำทุกครั้ง (ซึ่งอาจมีความสำคัญมาก) หากคุณกำลังจะใช้มันแบบวนซ้ำคุณจะได้รับความเร็วที่ดีขึ้นโดยใช้ความเข้าใจของเครื่องกำเนิดไฟฟ้า:

>>> y = ((x, bars) for x in foos)
>>> for z in y:
...     print z
...
(1.0, [1, 2, 3])
(2.0, [1, 2, 3])
(3.0, [1, 2, 3])
(4.0, [1, 2, 3])
(5.0, [1, 2, 3])

ความแตกต่างคือความเข้าใจกำเนิดจะโหลดอย่างเฉื่อยชา

UPDATE ในการตอบกลับความคิดเห็นนี้:

แน่นอนคุณรู้ว่าคุณไม่ได้คัดลอกแถบรายการทั้งหมดเป็นรายการแถบเดียวกัน ดังนั้นหากคุณแก้ไขอันใดอันหนึ่ง (รวมถึงแท่งต้นฉบับ) คุณจะแก้ไขทั้งหมด

ฉันคิดว่านี่เป็นจุดที่ถูกต้อง มีสองวิธีแก้ปัญหานี้ที่ฉันคิดได้ ประสิทธิภาพมากที่สุดน่าจะเป็นดังนี้:

tbars = tuple(bars)
[(x, tbars) for x in foos]

เนื่องจาก tuples ไม่เปลี่ยนรูปสิ่งนี้จะป้องกันไม่ให้แท่งถูกแก้ไขผ่านผลลัพธ์ของความเข้าใจรายการนี้ (หรือความเข้าใจของตัวสร้างหากคุณไปตามเส้นทางนั้น) หากคุณต้องการแก้ไขผลลัพธ์แต่ละรายการจริงๆคุณสามารถทำได้:

from copy import copy
[(x, copy(bars)) for x in foos]

อย่างไรก็ตามสิ่งนี้อาจมีราคาแพงเล็กน้อยทั้งในแง่ของการใช้หน่วยความจำและความเร็วดังนั้นฉันขอแนะนำให้ใช้มันเว้นแต่คุณจะต้องเพิ่มลงในแต่ละรายการ


1
แน่นอนคุณรู้ว่าคุณไม่ได้คัดลอกแถบรายการทั้งหมดเป็นรายการแถบเดียวกัน ดังนั้นหากคุณแก้ไขอันใดอันหนึ่ง (รวมถึงแท่งต้นฉบับ) คุณจะแก้ไขทั้งหมด
vartec

20

การเขียนโปรแกรมเชิงฟังก์ชันเป็นเรื่องเกี่ยวกับการสร้างโค้ดที่ไม่มีผลข้างเคียง

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

คุณกำลังพยายามใช้เป็นตัววนซ้ำ อย่าทำอย่างนั้น :)

นี่คือตัวอย่างวิธีที่คุณอาจใช้แผนที่เพื่อสร้างรายการที่คุณต้องการ มีวิธีแก้ปัญหาสั้น ๆ (ฉันแค่ใช้ความเข้าใจ) แต่สิ่งนี้จะช่วยให้คุณเข้าใจว่าแผนที่ทำอะไรได้ดีขึ้นเล็กน้อย:

def my_transform_function(input):
    return [input, [1, 2, 3]]

new_list = map(my_transform, input_list)

ในตอนนี้คุณได้ทำการจัดการข้อมูลเท่านั้น ตอนนี้คุณสามารถพิมพ์ได้:

for n,l in new_list:
    print n, ll

- ฉันไม่แน่ใจว่าคุณหมายถึงอะไรโดย "ไม่มีลูป" fp ไม่ได้เกี่ยวกับการหลีกเลี่ยงการวนซ้ำ (คุณไม่สามารถตรวจสอบทุกรายการในรายการโดยไม่ต้องเข้าไปที่แต่ละรายการ) มันเกี่ยวกับการหลีกเลี่ยงผลข้างเคียงดังนั้นการเขียนจุดบกพร่องให้น้อยลง



11
import itertools

foos=[1.0, 2.0, 3.0, 4.0, 5.0]
bars=[1, 2, 3]

print zip(foos, itertools.cycle([bars]))

นี่เป็นวิธีที่ง่ายที่สุดและใช้งานได้อย่างถูกต้อง โปรดยอมรับสิ่งนี้เป็นคำตอบ
Phyo Arkar Lwin

1
นี่เป็นเพียงรหัส ไม่มีคำอธิบายใด ๆ ผู้ใช้หลายคนไม่เข้าใจว่าคำตอบนี้หมายถึงอะไร @PhyoArkarLwin
ProgramFast

6

นี่คือภาพรวมของพารามิเตอร์ของmap(function, *sequences)ฟังก์ชัน:

  • function คือชื่อฟังก์ชันของคุณ
  • sequencesคือลำดับจำนวนเท่าใดก็ได้ซึ่งโดยปกติจะเป็นรายการหรือสิ่งที่เพิ่มขึ้น mapจะย้ำกว่าพวกเขาไปพร้อม ๆ กันfunctionและให้ค่าปัจจุบัน นั่นเป็นเหตุผลที่จำนวนลำดับควรเท่ากับจำนวนพารามิเตอร์ในฟังก์ชันของคุณ

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

ใช้วิธีแก้ปัญหาเช่นตัวแปรส่วนกลางหรือการทำความเข้าใจรายการตามที่คนอื่นแนะนำ


0

จะทำได้ไหม

foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3]

def maptest2(bar):
  print bar

def maptest(foo):
  print foo
  map(maptest2, bars)

map(maptest, foos)

1
คุณอาจต้องการเรียกพารามิเตอร์สำหรับ maptest2 () บางอย่างเช่น "บาร์" เอกพจน์barหมายความว่ามันได้รับค่าที่ทำซ้ำเมื่อคุณต้องการทั้งรายการจริงๆ
Nikhil Chelliah

1
ฉันเชื่อว่ามันได้รับค่าซ้ำ
คริส

0

แล้วสิ่งนี้ล่ะ:

foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3]

def maptest(foo, bar):
    print foo, bar

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