在PythonV中交错两个不同长度的列表。2.

在PythonV中交错两个不同长度的列表。2.,python,python-2.7,Python,Python 2.7,我正在尝试编写一个Python函数,它将两个列表作为参数并将它们交错。应保留组件列表的顺序。如果列表的长度不同,则较长列表中的元素应以相同的长度结束 结果列表的结尾。 例如,我想把它放在Shell中: interleave(["a", "b"], [1, 2, 3, 4]) 把这个拿回来: ["a", 1, "b", 2, 3, 4] 如果您能帮助我,我将不胜感激。以下是我将如何使用itertools模块的各种位来完成这项工作。它适用于任意数量的iterables,而不仅仅是两个: from

我正在尝试编写一个Python函数,它将两个列表作为参数并将它们交错。应保留组件列表的顺序。如果列表的长度不同,则较长列表中的元素应以相同的长度结束 结果列表的结尾。 例如,我想把它放在Shell中:

interleave(["a", "b"], [1, 2, 3, 4])
把这个拿回来:

["a", 1, "b", 2, 3, 4]

如果您能帮助我,我将不胜感激。

以下是我将如何使用
itertools
模块的各种位来完成这项工作。它适用于任意数量的iterables,而不仅仅是两个:

from itertools import chain, izip_longest # or zip_longest in Python 3
def interleave(*iterables):

    sentinel = object()
    z = izip_longest(*iterables, fillvalue = sentinel)
    c = chain.from_iterable(z)
    f = filter(lambda x: x is not sentinel, c)

    return list(f)
你可以试试这个:

In [30]: from itertools import izip_longest

In [31]: l = ['a', 'b']

In [32]: l2 = [1, 2, 3, 4]

In [33]: [item for slist in izip_longest(l, l2) for item in slist if item is not None]
Out[33]: ['a', 1, 'b', 2, 3, 4]
izip_longest
将两个列表“拉链”在一起,但它不会在最短列表的长度处停止,而是继续,直到最长的列表耗尽:

In [36]: list(izip_longest(l, l2))
Out[36]: [('a', 1), ('b', 2), (None, 3), (None, 4)]
然后,通过迭代压缩列表中每对中的每个项目来添加项目,忽略那些值为
None
的项目。正如@Blckknight所指出的,如果您的原始列表已经有
None
值,则此功能将无法正常运行。如果在您的情况下可以这样做,您可以使用
izip_longest
fillvalue
属性来填充
None
以外的内容(正如@Blckknight在其回答中所做的)

以下是作为函数的上述示例:

In [37]: def interleave(*iterables):
   ....:     return [item for slist in izip_longest(*iterables) for item in slist if item is not None]
   ....:

In [38]: interleave(l, l2)
Out[38]: ['a', 1, 'b', 2, 3, 4]

In [39]: interleave(l, l2, [44, 56, 77])
Out[39]: ['a', 1, 44, 'b', 2, 56, 3, 77, 4]

这不是一个非常优雅的解决方案,但仍然可能有帮助

def interleave(lista, listb):
    (tempa, tempb) = ([i for i in reversed(lista)], [i for i in reversed(listb)])
    result = []
    while tempa or tempb:
        if tempa:
            result.append(tempa.pop())
        if tempb:
            result.append(tempb.pop())

    return result
或者在一行中

   def interleave2(lista, listb):
    return reduce(lambda x,y : x + y,
                  map(lambda x: x[0] + x[1],
                      [(lista[i:i+1], listb[i:i+1])
                       for i in xrange(max(len(lista),len(listb)))]))

另一个解决方案是基于:我将如何手工完成?好的,几乎是手工操作,使用内置的
zip()
,并将压缩结果从较短列表的长度扩展到较长列表的尾部:

#!python2

def interleave(lst1, lst2):
    minlen = min(len(lst1), len(lst2))        # find the length of the shorter
    tail = lst1[minlen:] + lst2[minlen:]      # get the tail
    result = []
    for t in zip(lst1, lst2):                 # use a standard zip
        result.extend(t)                      # expand tuple to two items
    return result + tail                      # result of zip() plus the tail

print interleave(["a", "b"], [1, 2, 3, 4])
print interleave([1, 2, 3, 4], ["a", "b"])
print interleave(["a", None, "b"], [1, 2, 3, None, 4])
它将打印结果:

['a', 1, 'b', 2, 3, 4]
[1, 'a', 2, 'b', 3, 4]
['a', 1, None, 2, 'b', 3, None, 4]

您的版本无法处理包含
None
作为值的列表。这就是为什么我在我的版本中创建了一个唯一的sentinel对象,这样它就不会被列表中已经存在的任何奇怪的值绊倒。@Blckknght Gotcha-你的版本很好,我同意:)我会编辑答案来提一下。