แทรกรายการหลายรายการที่มีความยาวเท่ากันใน Python


86

ใน Python มีวิธีที่ดีในการแทรกสองรายการที่มีความยาวเท่ากันหรือไม่?

บอกว่าฉันได้รับและ[1,2,3] [10,20,30]ฉันต้องการแปลงร่างเป็น[1,10,2,20,3,30].


ไม่แนะนำให้ลองทำดังนี้it = iter(l1); list((yield next(it)) or i for i in l2)
Chris_Rands

สิ่งนี้ตอบคำถามของคุณหรือไม่? วิธี Pythonic ในการรวมสองรายการในแบบสลับกัน?
Vaidøtas I.

คำตอบ:


115

หลังจากโพสต์คำถามฉันได้ตระหนักว่าฉันสามารถทำสิ่งต่อไปนี้ได้:

[val for pair in zip(l1, l2) for val in pair]

ทั้งสองรายการอยู่ที่ไหนl1และอยู่ที่ไหนl2


หากมี N รายการที่จะแทรกระหว่างนั้น

lists = [l1, l2, ...]
[val for tup in zip(*lists) for val in tup]

5
ใช้งานได้ก็ต่อเมื่อ l1 และ l2 มีจำนวนองค์ประกอบเท่ากัน
Emmanuel

15
@ เอมมานูเอล: คำถามอ่านว่า "ใน Python มีวิธีที่ดีในการแทรกสองรายการที่มีความยาวเท่ากันหรือไม่"
NPE

1
หากคุณต้องการเพิ่มรายชื่อที่ยาวที่สุดให้ใช้izip_longestสำหรับ python2 และzip_longestสำหรับ python3 ` [val for pair in itertools.zip_longest(l1, l2) for val in pair]ผลลัพธ์ด้วย['a', 'b', 'a', 'b', 'a', 'b', None, 'b', None, 'b', None, 'b']
Sergey Zakharov

72

สำหรับ Python> = 2.3 มีไวยากรณ์ส่วนขยาย :

>>> a = [0, 2, 4, 6, 8]
>>> b = [1, 3, 5, 7, 9]
>>> c = a + b
>>> c[::2] = a
>>> c[1::2] = b
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

เส้นc = a + bนี้ใช้เป็นวิธีง่ายๆในการสร้างรายการใหม่ที่มีความยาวพอดีเป๊ะ (ในขั้นตอนนี้เนื้อหาไม่สำคัญ) สองบรรทัดถัดไปทำงานจริงของการแทรกสลับaและบรรทัดbแรกกำหนดองค์ประกอบของaดัชนีเลขคู่ทั้งหมดของc; คนที่สองกำหนดองค์ประกอบของทุกดัชนีเลขคี่ของbc


26

ให้

a = [1, 2, 3]
b = [10, 20, 30]
c = [100, 200, 300, 999]

รหัส

สมมติว่ารายการมีความยาวเท่ากันคุณจะได้รับรายการแทรกด้วยitertools.chainและzip:

import itertools


list(itertools.chain(*zip(a, b)))
# [1, 10, 2, 20, 3, 30]

ทางเลือก

itertools.zip_longest

โดยทั่วไปมีรายการที่ไม่เท่ากันให้ใช้zip_longest(แนะนำ):

[x for x in itertools.chain(*itertools.zip_longest(a, c)) if x is not None]
# [1, 100, 2, 200, 3, 300, 999]

หลายรายการสามารถแทรกได้อย่างปลอดภัย:

[x for x in itertools.chain(*itertools.zip_longest(a, b, c)) if x is not None]
# [1, 10, 100, 2, 20, 200, 3, 30, 300, 999]

more_itertools+

ห้องสมุดที่มาพร้อมกับroundrobinสูตรอาหาร itertools interleaveและinterleave_longest.

import more_itertools


list(more_itertools.roundrobin(a, b))
# [1, 10, 2, 20, 3, 30]

list(more_itertools.interleave(a, b))
# [1, 10, 2, 20, 3, 30]

list(more_itertools.interleave_longest(a, c))
# [1, 100, 2, 200, 3, 300, 999]

yield from

สุดท้ายสำหรับสิ่งที่น่าสนใจใน Python 3 (แต่ไม่แนะนำ):

list(filter(None, ((yield from x) for x in zip(a, b))))
# [1, 10, 2, 20, 3, 30]

list([(yield from x) for x in zip(a, b)])
# [1, 10, 2, 20, 3, 30]

+ติดตั้งโดยใช้pip install more_itertools


8

ฉันต้องการวิธีดำเนินการกับรายการขนาดต่างๆซึ่งคำตอบที่ยอมรับไม่ได้อยู่

โซลูชันของฉันใช้เครื่องกำเนิดไฟฟ้าและการใช้งานดูดีกว่าเล็กน้อยเนื่องจาก:

def interleave(l1, l2):
    iter1 = iter(l1)
    iter2 = iter(l2)
    while True:
        try:
            if iter1 is not None:
                yield next(iter1)
        except StopIteration:
            iter1 = None
        try:
            if iter2 is not None:
                yield next(iter2)
        except StopIteration:
            iter2 = None
        if iter1 is None and iter2 is None:
            raise StopIteration()

และการใช้งาน:

>>> a = [1, 2, 3, 4, 5]
>>> b = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> list(interleave(a, b))
[1, 'a', 2, 'b', 3, 'c', 4, 'd', 5, 'e', 'f', 'g']
>>> list(interleave(b, a))
['a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 'g']

roundrobinสูตรจากitertoolsโมดูลเป็นส่วนขยายทั่วไปมากกว่านี้
ShadowRanger

7

ทางเลือก:

>>> l1=[1,2,3]
>>> l2=[10,20,30]
>>> [y for x in map(None,l1,l2) for y in x if y is not None]
[1, 10, 2, 20, 3, 30]

ใช้งานได้เนื่องจากแผนที่ทำงานกับรายการแบบขนาน ใช้งานได้เหมือนกันภายใต้ 2.2 ด้วยตัวของมันเองด้วยNoneฟังก์ชันที่เรียกว่าmapสร้างรายการสิ่งที่เพิ่มขึ้น:

>>> map(None,l1,l2,'abcd')
[(1, 10, 'a'), (2, 20, 'b'), (3, 30, 'c'), (None, None, 'd')]

จากนั้นให้แบนรายการสิ่งที่ดึงดูด

แน่นอนข้อดีคือmap สามารถใช้ได้กับรายการจำนวนเท่าใดก็ได้และจะใช้ได้แม้ว่าจะมีความยาวต่างกัน:

>>> l1=[1,2,3]
>>> l2=[10,20,30]
>>> l3=[101,102,103,104]
>>> [y for x in map(None,l1,l2,l3) for y in x if y in not None]
[1, 10, 101, 2, 20, 102, 3, 30, 103, 104]

1
if yจะกรองออก0เช่นกันif y is not Noneเปราะบางน้อยลง
Jochen Ritzel

@Jochen Ritzel: ขอบคุณ! ฉันเห็นด้วยกับคุณ. แก้ไขแล้ว. ฉันเขียนด้วยกล้ามเนื้อเท่านั้น ...
หมาป่า

3

ฉันชอบวิธีแก้ปัญหาของ aix ที่สุด นี่เป็นอีกวิธีหนึ่งที่ฉันคิดว่าควรใช้ใน 2.2:

>>> x=range(3)
>>> x
[0, 1, 2]
>>> y=range(7,10)
>>> y
[7, 8, 9]
>>> sum(zip(x,y),[])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "tuple") to list
>>> sum(map(list,zip(x,y)),[])
[0, 7, 1, 8, 2, 9]

และอีกวิธีหนึ่ง:

>>> a=[x,y]
>>> [a[i][j] for j in range(3) for i in (0,1)]
[0, 7, 1, 8, 2, 9]

และ:

>>> sum((list(i) for i in zip(x,y)),[])
[0, 7, 1, 8, 2, 9]

รายการ (sum (zip (x, y), ())) จะดีกว่าไหม?
Veltzer Doron

0
[el for el in itertools.chain(*itertools.izip_longest([1,2,3], [4,5])) if el is not None]

ตราบเท่าที่คุณไม่มีสิ่งNoneที่คุณต้องการเก็บไว้


0

ในการตอบคำถาม "แทรกหลายรายการที่มีความยาวเท่ากันใน Python" เราสามารถสรุปคำตอบ 2 รายการของ @ekhumoro ได้ สิ่งนี้ต้องการอย่างชัดเจนว่ารายการมีความยาวเท่ากันซึ่งแตกต่างจากโซลูชัน (สง่างาม) โดย @NPE

import itertools

def interleave(lists):
    """Interleave a list of lists.

    :param lists: List of lists; each inner length must be the same length.
    :returns: interleaved single list
    :rtype: list

    """
    if len(set(len(_) for _ in lists)) > 1:
        raise ValueError("Lists are not all the same length!")
    joint = list(itertools.chain(*lists))
    for l_idx, li in enumerate(lists):
        joint[l_idx::len(lists)] = li
    return joint

ตัวอย่าง:

>>> interleave([[0,2,4], [1, 3, 5]])
[0, 1, 2, 3, 4, 5]
>>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12]])
[0, 1, 10, 2, 3, 11, 4, 5, 12]
>>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12], [13, 14, 15]])
[0, 1, 10, 13, 2, 3, 11, 14, 4, 5, 12, 15]
>>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12], [13, 14]])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 10, in interleave
ValueError: Lists are not all the same length!
>>> interleave([[0,2,4]])
[0, 2, 4]

0

สายเกินไปที่จะไปปาร์ตี้และมีคำตอบที่ดีมากมาย แต่ฉันอยากจะให้วิธีง่ายๆโดยใช้extend()วิธีการ:

list1 = [1, 2, 3]
list2 = [10, 20, 30]

new_list = []
for i in range(len(list1)):
    new_list.extend([list1[i], list2[i]])
print(new_list)

เอาท์พุต:

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