我有一个非常大的列表表列表,我需要添加更多列。
tbl = [range(200),range(200),range(200),...]
newCol = [val1, val2]
我看到它的方式我也可以这样做:
for idx,val in enumerate(tbl)
tbl[idx] = newCol + val
或
colRep = [newCol]*len(tbl)
mgr = itertools.izip(colRep,tbl)
newTbl = [ itertools.chain(*elem) for elem in mgr]
一个人真的比另一个好吗?有更好的方法吗?
答案 0 :(得分:2)
为了便于阅读,可以使用简单的列表解析:
In [28]: tbl = [range(2),range(3),range(4)]
In [29]: [newCol + list(elt) for elt in tbl]
Out[29]:
[['val1', 'val2', 0, 1],
['val1', 'val2', 0, 1, 2],
['val1', 'val2', 0, 1, 2, 3]]
请注意,在Python3中,range
返回范围对象,而不是列表。因此,为了使代码兼容Python2和Python3,我将newCol + elt
更改为newCol + list(elt)
。
如果您希望修改tbl
就地,可以使用
tbl[:] = [newCol + list(elt) for elt in tbl]
请注意,在我们比较性能之前,我们需要确定所需的结果,以免我们最终将苹果与橙子进行比较。
for-loop
修改tbl
到位。这是非常重要的吗?
zip/chain
代码不会就地修改tbl
而是生成一个列表
迭代器:
In [47]: newTbl
Out[47]:
[<itertools.chain at 0x7f5aeb0a6750>,
<itertools.chain at 0x7f5aeb0a6410>,
<itertools.chain at 0x7f5aeb0a6310>]
这可能是你想要的,但比较性能是不公平的
这两段代码,因为iterators
延迟了这个过程
枚举迭代器中的项。这就像计时一样
画房子和考虑画房子之间的区别。
为了使比较更公平,我们可以使用list来使用迭代器:
newTbl = [ list(itertools.chain(*elem)) for elem in mgr]
要对各种选项的效果进行基准测试,您可以使用timeit
,如下所示:
import timeit
import itertools
tbl = [range(2),range(3),range(4)]
newCol = ['val1', 'val2']
stmt = {
'for_loop' : '''\
for idx,val in enumerate(tbl):
tbl[idx] = newCol + val
''',
'list_comp': '''tbl = [newCol + elt for elt in tbl]''',
'inplace_list_comp': '''tbl[:] = [newCol + elt for elt in tbl]''',
'zip_chain': '''
colRep = [newCol]*len(tbl)
mgr = itertools.izip(colRep,tbl)
newTbl = [ list(itertools.chain(*elem)) for elem in mgr]
'''
}
for s in ('for_loop', 'list_comp', 'inplace_list_comp', 'zip_chain'):
t = timeit.timeit(
stmt[s],
setup='from __main__ import newCol, itertools; tbl = [range(200)]*10**5',
number=10)
print('{:20}: {:0.2f}'.format(s, t))
产量
for_loop : 1.12
list_comp : 1.21
inplace_list_comp : 1.26
zip_chain : 4.40
所以for_loop
可能会稍快一点。请务必使用tbl
进行检查
更接近你的实际用例。 timeit
结果可能会有所不同
原因,包括硬件,操作系统和软件版本。
另外请注意,如果这一点很少,这可能是无意义的预优化 一段代码不是实际代码中的重要瓶颈。例如, 如果您的实际代码在此列表理解中花费1.21秒而在1000 在其他地方几秒钟,这里十分之一秒的改善是微不足道的 整体。