Pythonic方式以交替的方式结合两个列表?
我有两个列表, 第一个列表保证只包含一个比第二个更多的项目 。 我想知道最Python化的方法来创build一个新的列表,其偶数索引值来自第一个列表,其奇数索引值来自第二个列表。
# 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的方法?
以下是切片的一种方法:
>>> 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']
在itertools
文档中有这样的配方:
from itertools import cycle, islice def roundrobin(*iterables): "roundrobin('ABC', 'D', 'EF') --> ADEBFC" # 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))
这应该做你想要的:
>>> iters = [iter(list1), iter(list2)] >>> print list(it.next() for it in itertools.cycle(iters)) ['f', 'hello', 'o', 'world', 'o']
import itertools print [x for x in itertools.chain.from_iterable(itertools.izip_longest(list1,list2)) if x]
我认为这是这样做的最pythonic的方式。
没有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')
我知道有两个问题,一个问题比另一个问题要多,但是我想我会把这个问题提供给其他可能会发现这个问题的人。
邓肯的解决scheme适用于两个不同大小的列表。
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 = [ item for pair in zip(list1, list2 + [0]) for item in pair][:-1]
这一个是基于卡洛斯瓦利恩特上面的贡献,可以select交替的多个项目组,并确保所有项目都出现在输出中:
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)]
这将交换列表A和B每组3个值:
['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]
我的拿:
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 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
这是一个使用列表parsing的单行,没有其他库:
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))]
停下来最短的时间:
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__方法可能会更快。
这是讨厌的,但不pipe列表的大小:
list3 = [element for element in list(itertools.chain.from_iterable([val for val in itertools.izip_longest(list1, list2)])) if element != None]
另外一个问题的答案是多方面的,
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]
我会做简单的:
chain.from_iterable( izip( list1, list2 ) )
它会提出一个迭代器,而不会创build任何额外的存储需求。
我太老了,不能用列表理解,所以:
import operator list3 = reduce(operator.add, zip(list1, list2))