Перемещение двух списков в Python

В Python есть ли хороший способ чередования двух списков одинаковой длины?

Скажем, мне дали [1,2,3] и [10,20,30] . Я хотел бы преобразовать их в [1,10,2,20,3,30] .

Выполнив этот вопрос, я понял, что могу просто сделать следующее:

 [val for pair in zip(l1, l2) for val in pair] 

где l1 и l2 – два списка.

Для python> = 2.3 существует расширенный синтаксис среза :

 >>> a = [0, 2, 4, 6, 8] >>> b = [1, 3, 5, 7, 9] >>> c = a + b >>> c[::2] = a >>> c[1::2] = b >>> c [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

Альтернатива:

 >>> l1=[1,2,3] >>> l2=[10,20,30] >>> [y for x in map(None,l1,l2) for y in x if y is not None] [1, 10, 2, 20, 3, 30] 

Это работает, потому что карта работает в списках параллельно. Он работает одинаково под 2.2. Сам по себе, когда None как вызываемые функции, map создает список кортежей:

 >>> map(None,l1,l2,'abcd') [(1, 10, 'a'), (2, 20, 'b'), (3, 30, 'c'), (None, None, 'd')] 

Затем просто сгладьте список кортежей.

Преимущество, конечно же, заключается в том, что map будет работать для любого количества списков и будет работать, даже если они имеют разную длину:

 >>> l1=[1,2,3] >>> l2=[10,20,30] >>> l3=[101,102,103,104] >>> [y for x in map(None,l1,l2,l3) for y in x if y in not None] [1, 10, 101, 2, 20, 102, 3, 30, 103, 104] 

Существует несколько вариантов.

 # Given a = [1, 2, 3] b = [10, 20, 30] 

Вы можете получить список с чередованием с помощью itertools :

 import itertools list(itertools.chain(*zip(a, b))) # [1, 10, 2, 20, 3, 30] 

Подумайте об установке more_itertools – библиотеки, которая поставляется с реализациями interleave , interleave_longest и рецепта roundrobin itertools .

 import more_itertools list(more_itertools.interleave(a, b)) # [1, 10, 2, 20, 3, 30] list(more_itertools.roundrobin(a, b)) # [1, 10, 2, 20, 3, 30] 

Наконец, для чего-то интересного, в Python 3:

 list(filter(None, ((yield from i) for i in zip(a, b)))) # [1, 10, 2, 20, 3, 30] 

Мне нужен был способ сделать это со списками разных размеров, которые не принимал принятый ответ.

Мое решение использует генератор, и его использование выглядит немного приятнее из-за этого:

 def interleave(l1, l2): iter1 = iter(l1) iter2 = iter(l2) while True: try: if iter1 != None: yield next(iter1) except StopIteration: iter1 = None try: if iter2 != None: yield next(iter2) except StopIteration: iter2 = None if iter1 == None and iter2 == None: raise StopIteration() 

И его использование:

 >>> a = [1, 2, 3, 4, 5] >>> b = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] >>> list(interleave(a, b)) [1, 'a', 2, 'b', 3, 'c', 4, 'd', 5, 'e', 'f', 'g'] >>> list(interleave(b, a)) ['a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 'g'] 

Мне больше нравится решение AIX. вот еще один способ, я думаю, должен работать в 2.2:

 >>> x=range(3) >>> x [0, 1, 2] >>> y=range(7,10) >>> y [7, 8, 9] >>> sum(zip(x,y),[]) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can only concatenate list (not "tuple") to list >>> sum(map(list,zip(x,y)),[]) [0, 7, 1, 8, 2, 9] 

и еще один способ:

 >>> a=[x,y] >>> [a[i][j] for j in range(3) for i in (0,1)] [0, 7, 1, 8, 2, 9] 

а также:

 >>> sum((list(i) for i in zip(x,y)),[]) [0, 7, 1, 8, 2, 9] 
 [el for el in itertools.chain(*itertools.izip_longest([1,2,3], [4,5])) if el is not None] 

Пока у вас нет None , которого вы хотите сохранить