【发布时间】:2020-07-10 14:03:50
【问题描述】:
假设我有多个 Python 列表。在多个 Python 列表的元素之间插入元素的一种快速方法是什么?
# Have
list1 = [1, 2, 3]
list2 = [10, 11, 12]
list3 = [20, 21, 22]
# Expect
list_between = [1, 10, 20, 2, 11, 21, 3, 12, 22]
【问题讨论】:
假设我有多个 Python 列表。在多个 Python 列表的元素之间插入元素的一种快速方法是什么?
# Have
list1 = [1, 2, 3]
list2 = [10, 11, 12]
list3 = [20, 21, 22]
# Expect
list_between = [1, 10, 20, 2, 11, 21, 3, 12, 22]
【问题讨论】:
list_between = [i for l in list(zip(list1, list2, list3)) for i in l]
只需使用 zip 并使用列表推导在元组列表中按顺序打印元素。
list(zip(list1, list2, list3)) # returns [(1, 10, 20), (2, 11, 21), (3, 12, 22)]
【讨论】:
itertools.recipes 中有roundrobin,可以做你想做的事:
from itertools import cycle, islice
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
num_active = len(iterables)
nexts = cycle(iter(it).__next__ for it in iterables)
while num_active:
try:
for next in nexts:
yield next()
except StopIteration:
# Remove the iterator we just exhausted from the cycle.
num_active -= 1
nexts = cycle(islice(nexts, num_active))
list1 = [1, 2, 3]
list2 = [10, 11, 12]
list3 = [20, 21, 22]
list_between = list(roundrobin(list1,list2,list3))
print(list_between)
输出:
[1, 10, 20, 2, 11, 21, 3, 12, 22]
请注意,它也适用于不同长度的参数(请参阅文档字符串)。
【讨论】:
如果你想将listB 中的元素插入listA 中的任意位置,可以使用list.insert(index, object_to_insert) 方法。
如果你非常关心速度,你应该知道这可能不会很快,因为 python 列表是implemented as dynamic arrays,而不是链表。为了更快地插入,您可能需要实现自己的链表类型。
如果您想完全按照您的示例所示的方式组合三个列表,您可以将它们插入到 numpy 数组中,然后对数组进行转置。
In [1]: import numpy as np
In [2]: listA = [1, 2, 3]
...: listB = [4, 5, 6]
...: listC = [7, 8, 9]
...:
...: arr = np.array([listA, listB, listC])
...: arr.T
Out[2]:
array([[1, 4, 7],
[2, 5, 8],
[3, 6, 9]])
In [3]: arr.T.flatten()
Out[3]: array([1, 4, 7, 2, 5, 8, 3, 6, 9])
In [4]: arr.T.flatten().tolist()
Out[4]: [1, 4, 7, 2, 5, 8, 3, 6, 9]
【讨论】:
np.transpose 是否适用于大型数据集或矩阵?我不确定 numpy 转置是如何工作的,但从理论上讲,为大型矩阵转置应该是相当昂贵的......?
你可以使用:
import itertools
list(itertools.chain.from_iterable(zip(list1, list2, list3)))
如果列表的长度不同,所有列表将被缩小到最短的长度。
【讨论】:
我不知道任何简单/快速的方法,但如果该示例具有代表性,您希望以这种方式从多个列表中构建列表,您可以这样做:
n = 3 # length of our lists, must all be the same for simple logic
our_lists = [list1, list2, list3]
new_list = []
for i in range(3):
for l in our_lists:
new_list.append(l[i])
【讨论】:
如果所有列表具有相同数量的元素,您可以在列表理解中使用 zip:
list_between = [ e for e3 in zip(list1,list2,list3) for e in e3 ]
【讨论】:
这是一种 hacky 方式,但与使用 np.transpose 相比要慢一些。这是通过使用slice 在元素之间插入0,然后将列表添加在一起来实现的:
# e.g.
# arr1 = [1, 0, 0, 2, 0, 0, 3, 0, 0]
# arr2 = [0, 1, 0, 0, 2, 0, 0, 3, 0]
# arr3 = [0, 0, 1, 0, 0, 2, 0, 0, 3]
#
# arr_ = [1, 1, 1, 2, 2, 2, 3, 3, 3] # use np.add to fast insert
list1 = np.insert(list1, slice(1, None, 1), 0) # create 0,0 paddings in between
list1 = np.insert(list1, slice(1, None, 2), 0)
list1 = np.insert(list1, 0, [0]*(0))
list1 = list1.tolist()
list1.extend([0]*(3-1))
list2 = np.insert(list2, slice(1, None, 1), 0)
list2 = np.insert(list2, slice(1, None, 2), 0)
list2 = np.insert(list2, 0, [0]*(0+1))
list2 = list2.tolist()
list2.extend([0]*(3-2))
list3 = np.insert(list3, slice(1, None, 1), 0)
list3 = np.insert(list3, slice(1, None, 2), 0)
list3 = np.insert(list3, 0, [0]*(0+2))
list3 = list3.tolist()
list3.extend([0]*(3-3))
list_ = np.add(list1, list2)
list_ = np.add(list_, list3)
list_
array([ 1, 10, 20, 2, 11, 21, 3, 12, 22])
【讨论】: