在以下情况下连接两个列表list_a
和list_b
的最有效方法是什么:
list_b
项必须放在list_a
项list_a
我有四种可能性:
# 1
list_a = list_b + list_a
# 2
for item in list_b:
list_a.insert(0, item)
# 3
for item in self.list_a:
list_b.append(item)
list_a = list_b
# 4
list_a[0:0] = list_b
谢谢!
答案 0 :(得分:22)
这是一个图表,显示BigYellowCactus答案中使用的计时如何随着列表长度的增加而发展。垂直轴是在usec中初始化两个列表并将一个列表插入另一个列表前所需的时间。横轴是列表中的项目数。
答案 1 :(得分:6)
鉴于此
list_a = list_b + list_a
适用于您的目的,因此您实际上并不需要list_a
对象本身来存储list_a
中的所有数据 - 您只需要名称 { {1}}(即,您没有或不关心任何其他可能引用相同列表的变量)。
如果您也不关心它只是一个列表,但只关于它是可迭代的,那么您可以使用list_a
:
itertools.chain
如果你做关心某些列表事项,你可以为list_a = itertools.chain(list_b, list_a)
构建一个类似于列表的东西 - 类似于:
chain
等。这需要花费很多精力(可能超过其价值)才能在所有情况下工作 - 例如,处理切片和负面索引会浮现在脑海中。但是对于非常简单的情况,这种方法可以避免大量复制列表内容。
答案 2 :(得分:5)
你可以将list_b分配给一个切片,该切片恰好是空的,但是在list_a的开头:
list_a[0:0] = list_b
这是在任何位置将列表插入另一个列表的最快方法。
答案 3 :(得分:4)
为什么不只是timeit
?
import timeit
create_data = """\
list_a = range(10)
list_b = range(10)
"""
t1 = timeit.Timer(stmt=create_data + """\
list_a = list_b + list_a
""")
t2 = timeit.Timer(create_data + """\
for item in list_b:
list_a.insert(0, item)
""")
t3 = timeit.Timer(create_data + """\
for item in list_a:
list_b.append(item)
list_a = list_b
""")
t4 = timeit.Timer(create_data + """\
list_a[0:0] = list_b
""")
for i, t in enumerate([t1,t2,t3,t4]):
print i, "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
<强>结果:强>
0 0.73 usec / pass
1 2.79 usec / pass
2 1.66 usec / pass
3 0.77 usec / pass
答案 4 :(得分:3)
试试这个:
list_a[0:0] = list_b
答案 5 :(得分:0)
itertools.chain
只是生成一个生成器,因此,如果您可以不用生成器而不是列表,那么生成的时间是固定的,但是在访问每个元素时您要付出代价。否则list_a[0:0] = list_b
比list_a = list_b + list_a
快6倍
我认为list_a = list_b + list_a
是最易读的选择,而且已经非常快了。
您提到的在append()
循环中使用for
的两种方法的速度实在太慢了,因此我不必理会它们。
在具有16 GB 2133 MHz LPDDR3 RAM的1.6 GHz双核Intel Core i5上运行Python 3.7.5 [Clang 11.0.0 (clang-1100.0.33.8)] on darwin
,
from timeit import timeit
import random
import matplotlib.pyplot as plt
num_data_points = 1000
step = 10
methods = [
# ordered from slowest to fastest to make the key easier to read
# """for item in list_a: list_b.append(item); list_a = list_b""",
# """for item in list_b: list_a.insert(0, item)""",
# "list_a = list(itertools.chain(list_b, list_a))",
"list_a = list_b + list_a",
"list_a[0:0] = list_b",
"list_a = itertools.chain(list_b, list_a)",
]
x = list(range(0, num_data_points * step, step))
y = [[] for _ in methods]
for i in x:
list_a = list(range(i))
list_b = list(range(i))
random.shuffle(list_a)
random.shuffle(list_b)
setup = f"list_a = {list_a}; list_b = {list_b}"
for method_index, method in enumerate(methods):
y[method_index].append(timeit(method, setup=setup, number=30))
print(i, "out of", num_data_points * step)
ax = plt.axes()
for method_index, method in enumerate(methods):
ax.plot(x, y[method_index], label=method)
ax.set(xlabel="number of elements in both lists", ylabel="time (s) (lower is better)")
ax.legend()
plt.show()