รับแผนที่ () เพื่อส่งคืนรายการใน Python 3.x


523

ฉันพยายามแมปรายการเป็นเลขฐานสิบหกจากนั้นใช้รายการที่อื่น ใน python 2.6 มันง่ายมาก:

A: Python 2.6:

>>> map(chr, [66, 53, 0, 94])
['B', '5', '\x00', '^']

อย่างไรก็ตามใน Python 3.1 ข้างต้นจะส่งคืนวัตถุแผนที่

B: Python 3.1:

>>> map(chr, [66, 53, 0, 94])
<map object at 0x00AF5570>

ฉันจะดึงรายการที่แมป (เช่นเดียวกับAข้างบน) บน Python 3.x ได้อย่างไร

หรือมีวิธีที่ดีกว่าในการทำเช่นนี้? วัตถุรายการเริ่มต้นของฉันมีประมาณ 45 รายการและรหัสชอบแปลงเป็นเลขฐานสิบหก


2
มัน pythonic มากขึ้นที่จะใช้ความเข้าใจรายการ map()ถูกเกือบจะถูกลบออกจากภาษาที่เพราะมีเหตุผลที่จะใช้มันมากกว่าความเข้าใจรายการหรือไม่มีforห่วง
Boris

คำตอบ:


771

ทำเช่นนี้:

list(map(chr,[66,53,0,94]))

ใน Python 3+ กระบวนการจำนวนมากที่วนซ้ำ iterables จะส่งคืนตัววนซ้ำเอง ในกรณีส่วนใหญ่สิ่งนี้จบลงด้วยการประหยัดหน่วยความจำและควรทำให้ทุกอย่างรวดเร็วขึ้น

หากสิ่งที่คุณต้องทำคือวนซ้ำในรายการนี้ในที่สุดคุณไม่จำเป็นต้องแปลงเป็นรายการอีกต่อไปเพราะคุณยังสามารถทำซ้ำmapวัตถุได้โดยทำดังนี้

# Prints "ABCD"
for ch in map(chr,[65,66,67,68]):
    print(ch)

15
แน่นอนคุณสามารถทำซ้ำสิ่งนี้ได้เช่นกัน: (chr (x) สำหรับ x ใน [65,66,67,68] มันไม่จำเป็นต้องมีแผนที่ด้วยซ้ำ
hughdbrown

2
@hughdbrown อาร์กิวเมนต์สำหรับการใช้ 3.1 mapจะเป็นการประเมินผลที่ขี้เกียจเมื่อทำซ้ำในฟังก์ชันที่ซับซ้อนชุดข้อมูลขนาดใหญ่หรือสตรีม
Andrew Keeton

18
@ แอนดรูว์จริง ๆ แล้วฮิวจ์กำลังใช้เครื่องกำเนิดความเข้าใจซึ่งจะทำสิ่งเดียวกัน หมายเหตุวงเล็บไม่ใช่วงเล็บเหลี่ยม
Triptych

5
โซลูชันสำรอง (เร็วกว่าสำหรับอินพุตขนาดใหญ่ด้วย) เมื่อทราบว่าค่าเป็น ASCII / latin-1 จะทำการแปลงเป็นกลุ่มที่เลเยอร์ C: bytes(sequence_of_ints_in_range_0_to_256).decode('latin-1')ซึ่งทำให้strเร็วขึ้นโดยการหลีกเลี่ยงการเรียกใช้ฟังก์ชัน Python สำหรับแต่ละองค์ประกอบในการแปลงจำนวนมาก องค์ประกอบทั้งหมดที่ใช้การเรียกฟังก์ชั่นระดับ C เท่านั้น คุณสามารถใส่คำสั่งด้านบนlistถ้าคุณต้องการlistตัวละครแต่ละตัว แต่เนื่องจากstrตัวละครของมันซ้ำแล้วซ้ำอีกเหตุผลเดียวที่คุณทำเช่นนั้นคือถ้าคุณต้องการความไม่แน่นอน
ShadowRanger

1
list (map (str, [1,2,3])) ให้ "Error in argument" สำหรับ Python 3.4.3 บน CentOS 7 รายการความเข้าใจทำงานได้
Andor

108

ใหม่และเรียบร้อยใน Python 3.5:

[*map(chr, [66, 53, 0, 94])]

ขอบคุณที่มีการแกะทั่วไปเพิ่มเติม

UPDATE

ค้นหาวิธีที่สั้นกว่าเสมอฉันค้นพบวิธีนี้ได้ผล:

*map(chr, [66, 53, 0, 94]),

การเปิดออกยังทำงานในสิ่งอันดับด้วยเช่นกัน สังเกตเครื่องหมายจุลภาคในตอนท้าย สิ่งนี้ทำให้มันเป็น tuple ของ 1 องค์ประกอบ นั่นคือมันเทียบเท่ากับ(*map(chr, [66, 53, 0, 94]),)

มันสั้นกว่าถ่านหนึ่งตัวจากรุ่นที่มี list-brackets แต่ในความคิดของฉันดีกว่าที่จะเขียนเพราะคุณเริ่มต้นด้วยเครื่องหมายดอกจัน - ไวยากรณ์การขยายตัวดังนั้นฉันจึงรู้สึกเบาลงในใจ :)


11
@Quelklef list()ดูไม่เรียบร้อย
Arijoon

5
@Quelklef: นอกจากนี้วิธีการเปิดกล่องบรรจุทำได้เร็วขึ้นเล็กน้อยเนื่องจากไม่ต้องการค้นหาคอนlistสตรัคเตอร์และเรียกใช้ฟังก์ชันการโทรทั่วไป สำหรับอินพุตที่ยาวมันจะไม่สำคัญ สำหรับสั้น ๆ มันสามารถสร้างความแตกต่างใหญ่ การใช้รหัสด้านบนกับอินพุตtupleเพื่อไม่ให้สร้างใหม่ซ้ำ ๆipythonเครื่องหมายไมโครบล็อกแสดงว่าlist()วิธีการห่อใช้เวลานานกว่าการเปิดออกประมาณ 20% ในใจคุณในแง่สมบูรณ์เรากำลังพูดถึง 150 ns ซึ่งไม่สำคัญ แต่คุณได้รับความคิด
ShadowRanger

มีอะไรผิดปกติกับคนเก่าmapหรือไม่ อาจใช้ชื่อใหม่ ( lmap?) หากค่าเริ่มต้นใหม่คือส่งคืนตัววนซ้ำ?
Giorgio

1
*map()ให้ข้อผิดพลาดทางไวยากรณ์กับPython 3.6: can't use starred expression here. คุณต้องใส่มันในlist:[ *map() ]
ALH

4
@ALH คุณพลาดเครื่องหมายจุลภาคในตอนท้ายของคำสั่ง ทำผิดพลาดง่าย ๆ !
LondonRob

103

ทำไมคุณไม่ทำเช่นนี้:

[chr(x) for x in [66,53,0,94]]

มันเรียกว่าความเข้าใจในรายการ คุณสามารถค้นหาความอุดมสมบูรณ์ของข้อมูลเกี่ยวกับ Google แต่นี่คือการเชื่อมโยงไปหลาม (2.6) เอกสารเกี่ยวกับ comprehensions คุณอาจสนใจเอกสาร Python 3มากขึ้น


4
hmmmm อาจจะต้องมีการโพสต์ทั่วไปในรายการความเข้าใจเครื่องกำเนิดไฟฟ้า, แผนที่ (), zip () และความดีย้ำอีกรอบที่รวดเร็วในไพ ธ อน
hughdbrown

46
ฉันเดาว่าเพราะมันละเอียดมากขึ้นคุณต้องเขียนตัวแปรเพิ่มเติม (สองครั้ง) ... หากการดำเนินการนั้นซับซ้อนมากขึ้นและคุณจบลงด้วยการเขียนแลมบ์ดาหรือคุณต้องการวางองค์ประกอบบางอย่างฉันคิดว่าความเข้าใจนั้นดีกว่า มากกว่าตัวกรอง map + แต่ถ้าคุณมีฟังก์ชั่นที่คุณต้องการใช้แล้วแผนที่ก็จะกระชับมากขึ้น
fortran

1
+1: อ่านและอนุญาตให้คุณใช้ฟังก์ชั่นที่มีพารามิเตอร์มากมายได้ง่ายขึ้น
Le Droid

7
map(chr, [66,53,0,94])มีความกระชับมากกว่า[chr(x) for x in [66,53,0,94]]แน่นอน
Giorgio

เร็วกว่าคำตอบอื่น ๆ
Evhz

25

ฟังก์ชั่นแผนที่กลับรายการมีข้อได้เปรียบของการบันทึกการพิมพ์โดยเฉพาะในช่วงการโต้ตอบ คุณสามารถกำหนดlmapฟังก์ชั่น (ในการเปรียบเทียบของ python2 imap) ที่ส่งคืนรายการ:

lmap = lambda func, *iterable: list(map(func, *iterable))

แล้วโทรlmapแทนmapจะทำงาน: lmap(str, x)สั้นโดย 5 ตัวอักษร (30% ในกรณีนี้) กว่าและแน่นอนสั้นกว่าlist(map(str, x)) [str(v) for v in x]คุณสามารถสร้างฟังก์ชั่นที่คล้ายกันได้filterเช่นกัน

มีความคิดเห็นต่อคำถามเดิม:

ฉันขอแนะนำให้เปลี่ยนชื่อเป็นรับ map () เพื่อส่งคืนรายการใน Python 3 * เนื่องจากใช้กับ Python3 ทุกรุ่น มีวิธีทำเช่นนี้หรือไม่? - meawoppl 24 มกราคมเวลา 17:58 น

มันเป็นไปได้ที่จะทำอย่างนั้น แต่มันก็เป็นความคิดที่ดีมาก เพื่อความสนุกนี่คือวิธีที่คุณจะทำได้ ( แต่ไม่ควร ):

__global_map = map #keep reference to the original map
lmap = lambda func, *iterable: list(__global_map(func, *iterable)) # using "map" here will cause infinite recursion
map = lmap
x = [1, 2, 3]
map(str, x) #test
map = __global_map #restore the original map and don't do that again
map(str, x) #iterator

4

แปลงความคิดเห็นเก่าของฉันสำหรับการแสดงผลที่ดีกว่า: สำหรับ "วิธีที่ดีกว่าการทำเช่นนี้" โดยmapสิ้นเชิงถ้าปัจจัยการผลิตของคุณเป็นที่รู้จักเป็นเลข ASCII ก็ทั่วไปได้เร็วขึ้นมากในการแปลงและถอดรหัสลาbytes bytes(list_of_ordinals).decode('ascii')นั่นทำให้คุณได้รับstrค่า แต่ถ้าคุณต้องการความlistไม่แน่นอนหรือสิ่งที่คล้ายกันคุณสามารถแปลงได้ (และยังเร็วกว่า) ตัวอย่างเช่นในipythonmicrobenchmarks แปลง 45 อินพุต:

>>> %%timeit -r5 ordinals = list(range(45))
... list(map(chr, ordinals))
...
3.91 µs ± 60.2 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*map(chr, ordinals)]
...
3.84 µs ± 219 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*bytes(ordinals).decode('ascii')]
...
1.43 µs ± 49.7 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... bytes(ordinals).decode('ascii')
...
781 ns ± 15.9 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)

หากคุณปล่อยให้มันเป็น a strจะใช้เวลาประมาณ 20% ของเวลาในการmapแก้ปัญหาที่เร็วที่สุด แม้การแปลงกลับเป็นรายการก็ยังน้อยกว่า 40% ของmapโซลูชันที่เร็วที่สุด Bulk แปลงผ่านbytesและbytes.decodeแล้วกลุ่มแปลงกลับไปlistบันทึกจำนวนมากของการทำงานแต่เท่าที่สังเกตเห็นทำงานเฉพาะในกรณีที่ทุกปัจจัยการผลิตของคุณมีเลข ASCII (หรือในบางเลขหนึ่งไบต์ต่อการเข้ารหัสเฉพาะสถานที่ตัวละครเช่นlatin-1)


2
list(map(chr, [66, 53, 0, 94]))

map (func, * iterables) -> map map สร้าง iterator ที่คำนวณฟังก์ชันโดยใช้อาร์กิวเมนต์จากแต่ละ iterables หยุดเมื่อ iterable ที่สั้นที่สุดหมดลง

"สร้างตัววนซ้ำ"

หมายความว่ามันจะส่งคืนตัววนซ้ำ

"ที่คำนวณฟังก์ชันโดยใช้อาร์กิวเมนต์จากแต่ละ iterables"

หมายความว่าฟังก์ชั่นถัดไป () ของตัววนซ้ำจะรับค่าหนึ่งค่าของแต่ละตัววนซ้ำและส่งผ่านแต่ละค่าไปยังพารามิเตอร์ตำแหน่งหนึ่งตำแหน่งของฟังก์ชัน

ดังนั้นคุณจะได้รับตัววนซ้ำจากแผนที่ () funtion และ jsut ส่งผ่านไปยังรายการ () ฟังก์ชัน builtin หรือใช้รายการความเข้าใจ


2

นอกจากนี้ในการตอบข้างต้นPython 3เราก็อาจสร้างlistของค่าผลจากmapเป็น

li = []
for x in map(chr,[66,53,0,94]):
    li.append(x)

print (li)
>>>['B', '5', '\x00', '^']

เราอาจพูดคุยกันโดยตัวอย่างอื่นที่ฉันหลงการดำเนินการบนแผนที่สามารถจัดการในลักษณะที่คล้ายกันเช่นในregexปัญหาเราสามารถเขียนฟังก์ชั่นเพื่อรับlistรายการไปยังแผนที่และรับชุดผลลัพธ์ในเวลาเดียวกัน อดีต

b = 'Strings: 1,072, Another String: 474 '
li = []
for x in map(int,map(int, re.findall('\d+', b))):
    li.append(x)

print (li)
>>>[1, 72, 474]

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

2
เมื่อมีความเข้าใจในรายการอยู่แล้วฟังก์ชันรายการและคำตอบที่เปิดออกมาชัดเจนสำหรับลูปไม่เพิ่ม IMHO มาก
miradulo

1

คุณสามารถลองรับรายการจากวัตถุแผนที่โดยทำซ้ำแต่ละรายการในวัตถุและเก็บไว้ในตัวแปรที่แตกต่างกัน

a = map(chr, [66, 53, 0, 94])
b = [item for item in a]
print(b)
>>>['B', '5', '\x00', '^']

0

การใช้ list comprehension ใน python และยูทิลิตี้ฟังก์ชั่นการแมปพื้นฐานสามารถทำได้เช่นกัน:

chi = [x for x in map(chr,[66,53,0,94])]


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