[英]Pythonic way to mix two lists
我有两个长度为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
谁能建议一种更Python化的方式来做到这一点? 谢谢!
>>> 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()
产生一个具有最短参数长度的可迭代对象。 您可以将a[-1]
附加到结果中,也可以将itertools.zip_longest
(对于Python 2.x使用izip_longest)与填充值一起使用,然后删除该值。
您可以在此解决方案中使用两个以上的输入序列。
对于不附加最后一个值的情况,您可以尝试使用这种肮脏的方法,但是我并不推荐这样做,目前尚不清楚:
>>> 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,请使用single /
)
恕我直言,最好的方法是:
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]
>>> 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]
混合两个列表是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
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
我会结合使用以上答案:
>>> 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']
使用izip_longest
填补列表中没有的内容,或者不想保留结果。 如果您不想保留任何解析为False
,请使用izip_longest
和filter
的默认值:
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)))
为了提高效率,当l1
或l2
不是短列表而是很长或无限的可迭代对象时,请使用ifilter
代替filter
,它会为您提供可迭代对象,而不是将所有内存都放在列表中。 例:
from itertools import chain, izip_longest, ifilter
for value in ifilter(None, chain(*izip_longest(iter1,iter1))):
print value
sum([[x,y] for x,y in zip(b,a)],[])+[b[-1]]
注意:这仅适用于给定的列表长度,但可以轻松扩展到任意长度的列表。
这是我发现的最好的:
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
,不推荐了,使用列表理解 more-itertools具有roundrobin ,可以准确地完成此工作:
from more_itertools import roundrobin
l1 = [1, 3, 5]
l2 = [2, 4, 6, 8, 10]
print(list(roundrobin(l1,l2)))
# [1, 2, 1, 3, 4, 3, 5, 6, 5, 8, 10]
您可以执行以下操作(假设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)]
我在哪里使用/
进行整数除法(确切的运算符取决于语言版本)。
使用邮编。 这将为您提供一个元组列表,例如:[('a_1','b_1'),('a_2','b_2'),('a_3','b_3')]
如果要将其清理成一个不错的列表,只需使用enumerate遍历元组列表即可:
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']
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.