Pythonic方式以交替的方式组合两个列表?

时间:2010-09-09 17:11:35

标签: python

我有两个列表,第一个保证包含的项目比第二个多一个。我想知道最Pythonic的方法来创建一个新的列表,其偶数索引值来自第一个列表,其奇数索引值来自第二个列表。

# example inputs
list1 = ['f', 'o', 'o']
list2 = ['hello', 'world']

# desired output
['f', 'hello', 'o', 'world', 'o']

这很有效,但并不漂亮:

list3 = []
while True:
    try:
        list3.append(list1.pop(0))
        list3.append(list2.pop(0))
    except IndexError:
        break

如何才能实现这一目标?什么是最Pythonic方法?

21 个答案:

答案 0 :(得分:83)

这是切片的一种方法:

>>> list1 = ['f', 'o', 'o']
>>> list2 = ['hello', 'world']
>>> result = [None]*(len(list1)+len(list2))
>>> result[::2] = list1
>>> result[1::2] = list2
>>> result
['f', 'hello', 'o', 'world', 'o']

答案 1 :(得分:46)

itertools documentation中有一个配方:

from itertools import cycle, islice

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    pending = len(iterables)
    nexts = cycle(iter(it).next for it in iterables)
    while pending:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            pending -= 1
            nexts = cycle(islice(nexts, pending))

答案 2 :(得分:27)

这应该做你想要的:

>>> iters = [iter(list1), iter(list2)]
>>> print list(it.next() for it in itertools.cycle(iters))
['f', 'hello', 'o', 'world', 'o']

答案 3 :(得分:22)

import itertools
print [x for x in itertools.chain.from_iterable(itertools.izip_longest(list1,list2)) if x]

我认为这是最狡猾的做法。

答案 4 :(得分:11)

没有itertools并假设l1比l2长1项:

>>> sum(zip(l1, l2+[0]), ())[:-1]
('f', 'hello', 'o', 'world', 'o')

使用itertools并假设列表不包含None:

>>> filter(None, sum(itertools.izip_longest(l1, l2), ()))
('f', 'hello', 'o', 'world', 'o')

答案 5 :(得分:10)

我知道问题是关于两个列表,其中一个项目比另一个项目更多,但我想我会把这个放在可能会发现这个问题的其他人的名单上。

以下Duncan's solution适用于两个不同大小的列表。

list1 = ['f', 'o', 'o', 'b', 'a', 'r']
list2 = ['hello', 'world']
num = min(len(list1), len(list2))
result = [None]*(num*2)
result[::2] = list1[:num]
result[1::2] = list2[:num]
result.extend(list1[num:])
result.extend(list2[num:])
result

输出:

['f', 'hello', 'o', 'world', 'o', 'b', 'a', 'r'] 

答案 6 :(得分:7)

如果两个列表的长度相等,则可以执行以下操作:

[x for y in zip(list1, list2) for x in y]

由于第一个列表还有一个元素,因此您可以在事后添加它:

[x for y in zip(list1, list2) for x in y] + [list1[-1]]

答案 7 :(得分:4)

这是一个单行班轮:

list3 = [ item for pair in zip(list1, list2 + [0]) for item in pair][:-1]

答案 8 :(得分:2)

这是基于Carlos Valiente的贡献 可以选择替换多个项目的组,并确保输出中存在所有项目:

A=["a","b","c","d"]
B=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]

def cyclemix(xs, ys, n=1):
    for p in range(0,int((len(ys)+len(xs))/n)):
        for g in range(0,min(len(ys),n)):
            yield ys[0]
            ys.append(ys.pop(0))
        for g in range(0,min(len(xs),n)):
            yield xs[0]
            xs.append(xs.pop(0))

print [x for x in cyclemix(A, B, 3)]

这将按照每组3个值的组来交织A和B列表:

['a', 'b', 'c', 1, 2, 3, 'd', 'a', 'b', 4, 5, 6, 'c', 'd', 'a', 7, 8, 9, 'b', 'c', 'd', 10, 11, 12, 'a', 'b', 'c', 13, 14, 15]

答案 9 :(得分:1)

这是使用列表推导的一个班轮,没有其他库:

list3 = [sub[i] for i in range(len(list2)) for sub in [list1, list2]] + [list1[-1]]

如果您允许通过副作用更改初始列表1,这是另一种方法:

[list1.insert((i+1)*2-1, list2[i]) for i in range(len(list2))]

答案 10 :(得分:1)

我的看法:

a = "hlowrd"
b = "el ol"

def func(xs, ys):
    ys = iter(ys)
    for x in xs:
        yield x
        yield ys.next()

print [x for x in func(a, b)]

答案 11 :(得分:1)

def combine(list1, list2):
    lst = []
    len1 = len(list1)
    len2 = len(list2)

    for index in range( max(len1, len2) ):
        if index+1 <= len1:
            lst += [list1[index]]

        if index+1 <= len2:
            lst += [list2[index]]

    return lst

答案 12 :(得分:1)

可能会晚一点再购买另一条python单线版。当两个列表的大小相等或不相等时,此方法有效。一无是处的事情是它将修改a和b。如果有问题,则需要使用其他解决方案。

a = ['f', 'o', 'o']
b = ['hello', 'world']
sum([[a.pop(0), b.pop(0)] for i in range(min(len(a), len(b)))],[])+a+b
['f', 'hello', 'o', 'world', 'o']

答案 13 :(得分:0)

停止最短时间:

def interlace(*iters, next = next) -> collections.Iterable:
    """
    interlace(i1, i2, ..., in) -> (
        i1-0, i2-0, ..., in-0,
        i1-1, i2-1, ..., in-1,
        .
        .
        .
        i1-n, i2-n, ..., in-n,
    )
    """
    return map(next, cycle([iter(x) for x in iters]))

当然,解决下一个/ __ next__方法可能会更快。

答案 14 :(得分:0)

这很讨厌但无论列表大小如何都有效:

list3 = [element for element in list(itertools.chain.from_iterable([val for val in itertools.izip_longest(list1, list2)])) if element != None]

答案 15 :(得分:0)

answers to another question启发的多个单行:

import itertools

list(itertools.chain.from_iterable(itertools.izip_longest(list1, list2, fillvalue=object)))[:-1]

[i for l in itertools.izip_longest(list1, list2, fillvalue=object) for i in l if i is not object]

[item for sublist in map(None, list1, list2) for item in sublist][:-1]

答案 16 :(得分:0)

numpy怎么样?它也适用于字符串:

import numpy as np

np.array([[a,b] for a,b in zip([1,2,3],[2,3,4,5,6])]).ravel()

结果:

array([1, 2, 2, 3, 3, 4])

答案 17 :(得分:0)

一种功能不变的替代方法(Python 3):

from itertools import zip_longest
from functools import reduce

reduce(lambda lst, zipped: [*lst, *zipped] if zipped[1] != None else [*lst, zipped[0]], zip_longest(list1, list2),[])

答案 18 :(得分:-2)

我太老了,无法理解列表理解,所以:

import operator
list3 = reduce(operator.add, zip(list1, list2))

答案 19 :(得分:-2)

我会做的很简单:

chain.from_iterable( izip( list1, list2 ) )

它将提供一个迭代器而不会产生任何额外的存储需求。

答案 20 :(得分:-2)

from itertools import chain
list(chain(*zip('abc', 'def')))
['a', 'd', 'b', 'e', 'c', 'f']