วิธีการแปลงรายการ tuples เป็นหลายรายการ?


111

สมมติว่าฉันมีรายการสิ่งที่เพิ่มขึ้นและฉันต้องการแปลงเป็นหลายรายการ

ตัวอย่างเช่นรายการทูเปิลคือ

[(1,2),(3,4),(5,6),]

มีฟังก์ชันในตัวใน Python ที่แปลงเป็น:

[1,3,5],[2,4,6]

ซึ่งอาจเป็นโปรแกรมง่ายๆ แต่ฉันแค่อยากรู้เกี่ยวกับการมีอยู่ของฟังก์ชันในตัวใน Python

คำตอบ:


165

ฟังก์ชั่นในตัวzip()เกือบจะทำสิ่งที่คุณต้องการ:

>>> zip(*[(1, 2), (3, 4), (5, 6)])
[(1, 3, 5), (2, 4, 6)]

ข้อแตกต่างเพียงอย่างเดียวคือคุณได้รับ tuples แทนรายการ คุณสามารถแปลงเป็นรายการโดยใช้

map(list, zip(*[(1, 2), (3, 4), (5, 6)]))

40

จากเอกสาร python :

zip () ร่วมกับตัวดำเนินการ * สามารถใช้เพื่อคลายซิปรายการ:

ตัวอย่างเฉพาะ:

>>> zip((1,3,5),(2,4,6))
[(1, 2), (3, 4), (5, 6)]
>>> zip(*[(1, 2), (3, 4), (5, 6)])
[(1, 3, 5), (2, 4, 6)]

หรือถ้าคุณต้องการรายการจริงๆ:

>>> map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
[[1, 3, 5], [2, 4, 6]]


4

franklsf95 ไปเพื่อประสิทธิภาพในคำตอบของเขาและเลือกใช้list.append()แต่ไม่เหมาะสม

การเพิ่มความเข้าใจในรายการฉันได้สิ่งต่อไปนี้:

def t1(zs):
    xs, ys = zip(*zs)
    return xs, ys

def t2(zs):
    xs, ys = [], []
    for x, y in zs:
        xs.append(x)
        ys.append(y)
    return xs, ys

def t3(zs):
    xs, ys = [x for x, y in zs], [y for x, y in zs]
    return xs, ys

if __name__ == '__main__':
    from timeit import timeit
    setup_string='''\
N = 2000000
xs = list(range(1, N))
ys = list(range(N+1, N*2))
zs = list(zip(xs, ys))
from __main__ import t1, t2, t3
'''
    print(f'zip:\t\t{timeit('t1(zs)', setup=setup_string, number=1000)}')
    print(f'append:\t\t{timeit('t2(zs)', setup=setup_string, number=1000)}')
    print(f'list comp:\t{timeit('t3(zs)', setup=setup_string, number=1000)}')

สิ่งนี้ให้ผลลัพธ์:

zip:            122.11585397789766
append:         356.44876132614047
list comp:      144.637765085659

ดังนั้นหากคุณอยู่หลังการแสดงคุณควรใช้zip()แม้ว่าความเข้าใจในรายการจะไม่ไกลเกินไป ประสิทธิภาพของappendมันค่อนข้างแย่เมื่อเปรียบเทียบ


1

แม้จะ*zipเป็น Pythonic มากกว่า แต่โค้ดต่อไปนี้มีประสิทธิภาพที่ดีกว่ามาก:

xs, ys = [], []
for x, y in zs:
    xs.append(x)
    ys.append(y)

นอกจากนี้เมื่อรายการเดิมzsว่างเปล่า*zipจะเพิ่มขึ้น แต่รหัสนี้สามารถจัดการได้อย่างถูกต้อง

ฉันเพิ่งทำการทดลองอย่างรวดเร็วและนี่คือผลลัพธ์:

Using *zip:     1.54701614s
Using append:   0.52687597s

ทำงานได้หลายครั้งappendเร็วกว่า 3x - 4x zip! สคริปต์ทดสอบอยู่ที่นี่:

#!/usr/bin/env python3
import time

N = 2000000
xs = list(range(1, N))
ys = list(range(N+1, N*2))
zs = list(zip(xs, ys))

t1 = time.time()

xs_, ys_ = zip(*zs)
print(len(xs_), len(ys_))

t2 = time.time()

xs_, ys_ = [], []
for x, y in zs:
    xs_.append(x)
    ys_.append(y)
print(len(xs_), len(ys_))

t3 = time.time()

print('Using *zip:\t{:.8f}s'.format(t2 - t1))
print('Using append:\t{:.8f}s'.format(t3 - t2))

เวอร์ชัน Python ของฉัน:

Python 3.6.3 (default, Oct 24 2017, 12:18:40)
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

1

นอกจากคำตอบของ Claudiu แล้วคุณยังสามารถใช้:

>>>a, b = map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
>>>a
[1,3,5]
>>>b
[2,4,6]

แก้ไขโดย @Peyman mohseni kiasari


1
ไม่! มันจะทำให้คุณ(1, 3, 5)และ(2, 4, 6)ไม่ได้รายการ คุณควรใช้map(list, zip(*[(1, 2), (3, 4), (5, 6)]))
Peyman

0

การเพิ่มคำตอบของ Claudiu และ Claudiu และเนื่องจากต้องนำเข้าแผนที่จาก itertools ใน python 3 คุณจึงใช้ความเข้าใจในรายการเช่น:

[[*x] for x in zip(*[(1,2),(3,4),(5,6)])]
>>> [[1, 3, 5], [2, 4, 6]]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.