Pythonic方式混合两个列表

时间:2011-09-23 13:03:32

标签: python

我有两个长度为n和n + 1的列表:

[a_1, a_2, ..., a_n]
[b_1, b_2, ..., b_(n+1)]

我想要一个函数给出一个列表,其中包含来自两者的备用元素,即

[b_1, a_1, ..., b_n, a_n, b_(n+1)]

以下作品,但看起来并不聪明:

def list_mixing(list_long,list_short):
    list_res = []
    for i in range(len(list_short)):
        list_res.extend([list_long[i], list_short[i]])
    list_res.append(list_long[-1])
    return list_res

有人能建议采用更加pythonic的方式吗?谢谢!

12 个答案:

答案 0 :(得分:16)

>>> import itertools
>>> a
['1', '2', '3', '4', '5', '6']
>>> b
['a', 'b', 'c', 'd', 'e', 'f']
>>> list(itertools.chain.from_iterable(zip(a,b)))
['1', 'a', '2', 'b', '3', 'c', '4', 'd', '5', 'e', '6', 'f']

zip()生成一个具有最短参数长度的iterable。您可以将a[-1]附加到结果中,也可以使用填充值itertools.zip_longest(izip_longest for Python 2.x)并在之后删除该值。

此解决方案可以使用两个以上的输入序列。

如果不附加最后一个值,你可以尝试这种肮脏的方法,但我不是真的推荐它,不清楚:

>>> a
[1, 2, 3, 4, 5]
>>> b
['a', 'b', 'c', 'd', 'e', 'f']
>>> [a[i//2] if i%2 else b[i//2] for i in range(len(a)*2+1)]
['a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f']

(对于Python 2.x,使用单/

答案 1 :(得分:12)

恕我直言,最好的方法是:

result = [item for sublist in zip(a,b) for item in sublist]

它也比总和更快,并减少方式。

UPD 抱歉错过了您的第二个列表更大一个元素:) 还有另一种疯狂的方式:

result = [item for sublist in map(None, a, b) for item in sublist][:-1]

答案 2 :(得分:4)

>>> long = [1, 3, 5, 7]
>>> short = [2, 4, 6]
>>> mixed = []
>>> for i in range(len(long)):
>>>     mixed.append(long[i])
>>>     if i < len(short)
>>>         mixed.append(short[i])
>>> mixed
[1, 2, 3, 4, 5, 6, 7]

答案 3 :(得分:3)

混合两个列表是zip的作业:

res = []
for a,b in zip(list_long, list_short):
    res += [a,b]

对于不同长度的列表,定义自己的函数:

def mix(list_long, list_short):
    result = []
    i,j = iter(list_long), iter(list_short)
    for a,b in zip(i,j):
        res += [a,b]
    for rest in i:
        result += rest
    for rest in j:
        result += rest
    return result

使用answer given by Mihail,我们可以将其缩短为:

def mix(list_long, list_short):
    i,j = iter(list_long), iter(list_short)
    result = [item for sublist in zip(i,j) for item in sublist]
    result += [item for item in i]
    result += [item for item in j]
    return result

答案 4 :(得分:2)

我会结合使用以上答案:

>>> a = ['1', '2', '3', '4', '5', '6']

>>> b = ['a', 'b', 'c', 'd', 'e', 'f', 'g']

>>> [i for l in izip_longest(a, b, fillvalue=object) for i in l if i is not object]
<<< ['1', 'a', '2', 'b', '3', 'c', '4', 'd', '5', 'e', '6', 'f', 'g']

答案 5 :(得分:1)

sum([[x,y] for x,y in zip(b,a)],[])+[b[-1]]

注意:这仅适用于您给定的列表长度,但可以轻松扩展到任意长度列表。

答案 6 :(得分:1)

使用izip_longest填补您列表中没有的内容,或者不想保留结果。如果您不想保留任何解析为False的内容,请使用izip_longestfilter的默认值:

from itertools import chain, izip_longest
l1 = [1,3,5]
l2 = [2,4,6,8,10]
filter(None, chain(*izip_longest(l1,l2)))

结果是:[1, 2, 3, 4, 5, 6, 8, 10]

使用None填补空白并使用filter

删除这些空白
filter(lambda x: x is not None, chain(*izip_longest(l1,l2, fillvalue=None)))

为了提高效率,l1l2不是短名单,例如非常长或无限的迭代,而不是filter使用ifilter,它将为您提供迭代,而不是将所有内容放入列表中。例如:

from itertools import chain, izip_longest, ifilter
for value in ifilter(None, chain(*izip_longest(iter1,iter1))):
    print value

答案 7 :(得分:0)

您可以执行以下操作(假设为len(list_long)==len(list_short)+1

def list_mixing(list_long,list_short):
    return [(list_long[i/2] if i%2==0 else list_short[i/2]) for i in range(len(list_long)+len(list_short)]

我使用/进行整数除法(正是运算符的用途取决于语言版本)。

答案 8 :(得分:0)

这是我发现的最好的

import itertools

l1 = [1, 3, 5]
l2 = [2, 4, 6, 8, 10]

result = [
    x # do something
    for x in itertools.chain.from_iterable(itertools.zip_longest(l1, l2, l1))
    if x is not None
]
result
# [1, 2, 1, 3, 4, 3, 5, 6, 5, 8, 10]

为了更加清晰,zip_longest将每个索引的元素分组在一起:

iter = list(itertools.zip_longest(l1, l2, l1))
iter[0]
# (1, 2, 1)
iter[1]
# (3, 4, 3)
iter[-1] # last
# (None, 10, None)

之后,itertools.chain.from_iterable将它们按顺序展平。

最好的原因:

    不再建议
  • 过滤None,请使用列表理解
  • 列表理解还使您可以立即使用x“做某事”
  • 当某些列表比最短的列表长时,它不会丢弃项目
  • 它适用于任意数量的列表
  • 实际上很容易推断出发生了什么事,而与那里所有的“聪明”相反

答案 9 :(得分:0)

more-itertoolsroundrobin确实可以完成这项工作:

my_list = db_state.get(db_id)
if my_list is not None:
    print(f"This is list of db_nr and states for {db_id}:")
    for db_nr, status in my_list:
        print(f"{db_nr} is {status}")
else:
    print(f"No data for {db_id}!!")

答案 10 :(得分:0)

使用 zip_longest 并过滤掉末尾的 None 元素的不同长度和更多列表的另一个答案

from itertools import zip_longest
a = [1, 2, 3]
b = ['a', 'b', 'c', 'd']   
c = ['A', 'B', 'C', 'D', 'E']    
[item for sublist in zip_longest(*[a,b,c]) for item in sublist if item]

返回

[1, 'a', 'A', 2, 'b', 'B', 3, 'c', 'C', 'd', 'D', 'E']

答案 11 :(得分:-1)

使用zip。这会给你一个元组列表,如: [('a_1','b_1'),('a_2','b_2'),('a_3','b_3')]

如果你想把它清理成一个好的列表,只需用枚举迭代元组列表:

alist = ['a_1', 'a_2', 'a_3']
blist = ['b_1', 'b_2', 'b_3']
clist = []

for i, (a, b) in enumerate(zip(alist, blist)):
    clist.append(a)
    clist.append(b)
print clist
['a_1', 'b_1', 'a_2', 'b_2', 'a_3', 'b_3']