以交替方式合并两个列表的Python方式?
我有两个列表,第一个列表保证比第二个列表多包含一个项目。我想知道创建一个新列表的最python的方法,它的偶数索引值来自第一个列表,奇数索引值来自第二个列表以交替方式合并两个列表的Python方式?,python,Python,我有两个列表,第一个列表保证比第二个列表多包含一个项目。我想知道创建一个新列表的最python的方法,它的偶数索引值来自第一个列表,奇数索引值来自第二个列表 # example inputs list1 = ['f', 'o', 'o'] list2 = ['hello', 'world'] # desired output ['f', 'hello', 'o', 'world', 'o'] 这是可行的,但并不漂亮: list3 = [] while True: try:
# 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
除此之外,如何实现这一目标?什么是最具python风格的方法?下面是一个方法: 编辑: 对于大于3的python版本:
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))
在Python 2中,这应该满足您的要求:
>>> iters = [iter(list1), iter(list2)]
>>> print list(it.next() for it in itertools.cycle(iters))
['f', 'hello', 'o', 'world', 'o']
这里有一种通过切片实现的方法:
>>> 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']
我会做简单的事情:
chain.from_iterable( izip( list1, list2 ) )
它将提供一个迭代器,而不需要创建任何额外的存储需求。我太老了,无法理解列表,因此:
import operator
list3 = reduce(operator.add, zip(list1, list2))
这是一个单行程序:
list3=[item for pair in zip(list1,list2+[0])for item in pair][:-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))]
我的看法:
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)]
在最短的路线上停车:
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/uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
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
lst=[]
len1=len(列表1)
len2=len(列表2)
对于范围内的索引(最大值(len1,len2)):
如果索引+1没有itertools,并且假设l1比l2长1项:
>>> sum(zip(l1, l2+[0]), ())[:-1]
('f', 'hello', 'o', 'world', 'o')
在python 2中,使用itertools并假设列表不包含任何内容:
>>> filter(None, sum(itertools.izip_longest(l1, l2), ()))
('f', 'hello', 'o', 'world', 'o')
这是基于卡洛斯·瓦伦特的上述贡献 通过一个选项,可以交替多个项目组,并确保输出中存在所有项目:
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]
我知道这些问题是关于两个列表的,其中一个列表中的一项比另一项多,但我想我会把这个问题留给其他可能会发现这个问题的人 这里的内容适用于两个不同大小的列表
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']
这很糟糕,但不管列表的大小,都会起作用:
list3 = [element for element in list(itertools.chain.from_iterable([val for val in itertools.izip_longest(list1, list2)])) if element != None]
我认为这是最具python风格的方法。多行一行的灵感来自:
可能有点晚了再买一条python one班轮。当两个列表的大小相等或不相等时,此选项有效。一件毫无价值的事情是它会修改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']
努比怎么样?它也适用于字符串:
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])
一种功能性和不可变的替代方法(Python 3):
如果两个列表长度相等,则可以执行以下操作:
[x for y in zip(list1, list2) for x in y]
由于第一个列表还有一个元素,您可以在事后添加它:
[x for y in zip(list1, list2) for x in y] + [list1[-1]]
可能的重复不是重复!上面链接的文章中接受的答案产生了一个元组列表,而不是一个单一的合并列表。@Paul:是的,接受的答案没有给出完整的解决方案。阅读评论和其他答案。这个问题基本上是一样的,其他的解决方案也可以在这里应用。@Felix:我不同意。诚然,这些问题都在同一个社区,但实际上并不重复。作为模糊的证据,看看这里的潜在答案,并与其他问题进行比较。看看这些:它非常简单,但它只适用于相同长度的列表!您可以使用
chain来修复它。对于此处询问的特定问题,请从_iterable(izip(list1,list2),list1[len(list2):])
。。。列表1应该是较长的一个。是的,但我宁愿提出一个适用于任意长度容器的解决方案,或者屈服于上面提出的解决方案。我非常喜欢你最初的答案。虽然它并没有完美地解决这个问题,但合并两个相同长度的列表是一种优雅的方式。我建议在您当前的回答中保留它以及长度警告。如果列表1改为['f','o','o','d',],其最后一项('d')将不会出现在结果列表中(考虑到问题的具体情况,这完全可以)。这是一个优雅的解决方案@马克·耶普(我确实投了赞成票),只是指出了不同之处(如果其他人想要不同的行为,还有限制)+1来解决所陈述的问题,而且做得也很简单:-)我认为这样的事情是可能的。老实说,我认为这种情况下,roundrobin
函数有点过分了。要处理任何大小的列表,只需将迭代器中剩余的内容附加到结果:list(itertools.chain(map(next,itertools.cycle(iters)),*iters))
谢谢,邓肯。我没有意识到在切片时可以指定一个步骤。我喜欢这种方法的原因是它读起来很自然。1.列出正确的长度。2.用列表1的内容填充偶数索引。3.用列表2的内容填充奇数索引。在这种情况下,列表长度不同不是问题!我认为它只在len(list1)-len(list2)为0或1时有效。如果列表的长度合适,则它有效,如果长度不合适,则原始问题不会指定期望的答案。它可以很容易地修改,以处理最合理的情况:例如,如果您想忽略额外的元素,只需在开始之前砍掉较长的列表;如果您想让额外的元素与None交错,那么只需确保使用更多的None初始化结果;如果你想在末尾添加额外的元素,那么就忽略它们,然后附加它们。我也不清楚。我想指出的一点是,邓肯的解决方案与许多列出的解决方案不同,并没有因为列表长度不等而变得复杂。当然,它只适用于有限的情况,但我更喜欢在这种情况下工作的真正优雅的解决方案,而不是适用于任何两个列表的不那么优雅的解决方案。您可以使用(2*len(list1)-1)而不是(len(list1)+len(list2)),而且我更喜欢[0::2]而不是[::2]。这是正确的,但正如我所想的那样
array([1, 2, 2, 3, 3, 4])
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),[])
from itertools import chain
list(chain(*zip('abc', 'def'))) # Note: this only works for lists of equal length
['a', 'd', 'b', 'e', 'c', 'f']
[x for y in zip(list1, list2) for x in y]
[x for y in zip(list1, list2) for x in y] + [list1[-1]]