在Python中交错多个相同长度的列表

时间:2011-10-30 18:15:32

标签: python list

在Python中,是否有一种交错两个相同长度列表的好方法?

说我给了[1,2,3][10,20,30]。我想将它们转换为[1,10,2,20,3,30]

9 个答案:

答案 0 :(得分:88)

发布问题后,我意识到我可以简单地执行以下操作:

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

其中l1l2是两个列表。


如果有N个列表要交错,那么

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

如需更多食谱,请按Best way to interleave a list with its suffix values。所展示的一些方法可以推广到两个或更多个相等长度的列表。

答案 1 :(得分:48)

对于Python> = 2.3,有extended slice syntax

>>> 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用作创建完全正确长度的新列表的简单方法(在此阶段,其内容并不重要)。接下来的两行是交错ab的实际工作:第一行将a的元素分配给c的所有偶数索引;第二个将b的元素分配给c的所有奇数索引。

答案 2 :(得分:13)

<强>鉴于

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

<强>代码

假设长度相等的列表,您可以获得包含itertools.chainzip的交错列表:

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食谱,interleaveinterleave_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

安装

答案 3 :(得分:6)

替代:

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

这是有效的,因为map并行处理列表。它是works the same 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]

答案 4 :(得分:6)

我需要一种方法来处理接受的答案无法解决的不同大小的列表。

我的解决方案使用了一个生成器,因此它的用法看起来更好:

def interleave(l1, l2):
    iter1 = iter(l1)
    iter2 = iter(l2)
    while True:
        try:
            if iter1 != None:
                yield next(iter1)
        except StopIteration:
            iter1 = None
        try:
            if iter2 != None:
                yield next(iter2)
        except StopIteration:
            iter2 = None
        if iter1 == None and iter2 == 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']

答案 5 :(得分:2)

我最喜欢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]

答案 6 :(得分:0)

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

只要您没有要保留的None

答案 7 :(得分:0)

要回答“在Python中插入相同长度的多个列表”的问题标题,我们可以归纳@ekhumoro的2列表答案。这明确要求列表长度相同,这与@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]

答案 8 :(得分: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]