5

I am trying to write a Python function that takes two lists as arguments and interleaves them. The order of the component lists should be preserved. If the lists do not have the same length, the elements of the longer list should end up at the end of the resulting list. For example, I'd like to put this in Shell:

interleave(["a", "b"], [1, 2, 3, 4])

And get this back:

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

If you can help me I'd appreciate it.

4

4 回答 4

1

这就是我的做法,使用itertools模块的各个部分。它适用于任意数量的可迭代对象,而不仅仅是两个:

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)
于 2012-11-05T02:55:15.517 回答
1

你可以试试这个:

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. None正如@Blckknight 所指出的,如果您的原始列表已经有值,这将无法正常工作。如果在您的情况下这是可能的,您可以使用 of 的fillvalue属性izip_longest来填充其他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]
于 2012-11-05T03:00:09.810 回答
0

一个不是很优雅的解决方案,但仍然可能会有所帮助

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)))]))
于 2012-11-05T06:39:59.327 回答
0

另一种解决方案是基于:我将如何手动完成?好吧,几乎是手动的,使用内置的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]
于 2012-11-05T07:53:15.267 回答