我有一个由长度为5的元组组成的列表l
。前四个条目是字符串,最后一个是整数。
创建此类列表的虚函数可能如下所示:
import numpy as np
import uuid
def get_dummy_data(n=10000):
l = []
for i in range(n):
name = np.random.choice(["Cat", "Dog", "Duck"], 1)[0]
c_id = uuid.uuid4().hex
t_id = uuid.uuid4().hex
l.append((c_id, t_id, name, "canFly", 1))
if np.random.random() < 0.8:
l.append((c_id, t_id, name, "isHungry", 0))
return l
现在这个列表l
包含具有相同前三个元素但在后两个元素中不同的元组。这里通过再次附加相同的元组以80%的几率但更改最后两个元素来举例说明。
目标是将这个长度为5元组的列表转换为字典,其中键是元组的第一个条目(c_id),值的结构如下(t_id,(name,{&#34; isHungry&#34;:0}))或者:(t_id,(名称,{&#34; canFly&#34;:1,&#34; isHungry&#34;:0}))。
这可以通过以下循环实现:
res = {}
for y in l:
if y[0] not in res:
res[y[0]] = (y[1], (y[2], {y[3]: y[4]}))
else:
res[y[0]][1][1].update({y[3]: y[4]})
现在的问题是:我可以加快速度吗?列表l
中可能有两个以上的元组具有相同的c_id
(与get_dummy_data函数相反),我们不能假设l
中的任何顺序。
我总是有一种不好的感觉,当做一个明确的循环来填充一个字典,所以我打赌有一个很好的方法来使这更快。
答案 0 :(得分:2)
您可以进行基本的微优化,使您的代码更具可读性。较大的一个没有使用some_dict.update({x:y})
而不是some_dict[x] = y
。但是这里有一些时间差异:
In [12]: %%timeit
...: res = {}
...: for y in data:
...: if y[0] not in res:
...: res[y[0]] = (y[1], (y[2], {y[3]: y[4]}))
...: else:
...: res[y[0]][1][1].update({y[3]: y[4]})
...:
100 loops, best of 3: 15.3 ms per loop
In [13]: %%timeit
...: res = {}
...: for a,b,c,d,e in data:
...: if a not in res:
...: res[a] = (b, (c, {d: e}))
...: else:
...: res[a][1][1][d] = e
...:
100 loops, best of 3: 11 ms per loop
这是.update
。请注意,每个y[...]
都是一个方法调用,会减慢速度。但节省时间的最大部分是避免.update({...}
。注意,这种方法需要创建一个完整的dict
对象,没有充分的理由:
In [18]: %%timeit
...: res = {}
...: for a,b,c,d,e in data:
...: if a not in res:
...: res[a] = (b, (c, {d: e}))
...: else:
...: res[a][1][1].update({d:e})
...:
100 loops, best of 3: 13.8 ms per loop
答案 1 :(得分:1)
这种循环通常很慢:
res = {}
for y in l:
if y[0] not in res:
res[y[0]] = (y[1], (y[2], {y[3]: y[4]}))
else:
res[y[0]][1][1].update({y[3]: y[4]})
因为您正在测试密钥是否属于字典两次且是if/else
语句。
我会在lambda
&amp;中使用变量的绑定属性。拆包(从juanpa回答借来):
import collections
res = collections.defaultdict(lambda : (b, (c, {d: e})))
for a,b,c,d,e in l:
res[a][1][1][d] = e
如果密钥不在字典defaultdict
中,则使用a
,b
...的当前值创建密钥,(感谢lambda
评估值时的值执行,而不是在声明时)保存测试并每次创建正确的密钥。现在update
部分有点多余,但它仍然应该更快,因为没有if/then
测试。
这个解决方案比我的机器上的juanpa(已经很好)答案快(0.23秒vs 0.27秒)。我认为这是一个很好的合作努力,因为我的第一个版本速度较慢。