Python中有什么更好的选择?
dict
,每个密钥包含一个包含10个项目的list
dict
,每个密钥包含一个带有10个“子密钥”的dict
dict
,每个子密钥包含一个带有10000个密钥的dict
选项2似乎比选项1对程序员更友好(例如,使用mydict['long-ID1']['street']
而不是mydict['long-ID1'][3]
)。
但是,我担心这可能会导致不必要的开销。我不希望子键的数量或顺序(例如'street'
)将来会发生变化。
我正在根据性能(查找速度)寻找“最佳”选项,同时还在考虑存储空间(在RAM以及使用泡菜保存时。)
背景
我正在解析具有以下列的〜10000行(工作站)的〜4MB CSV文件:
ID -唯一〜30个字符串
名称,街道,城市... -字符串
纬度,经度-GPS坐标
日期-猜一猜
jsonstring -一些嵌套的字典
我想使用 ID 作为密钥将数据作为dict station
导入python,以允许快速查找station['some-id']
。然后,我将在dict中执行几百万次查找,通常只根据每个用例查看每个工作站10列中的1-2列。
这就是为什么在写这个问题时,我想到了选项3 ...我看到的缺点是10000个键比10个键长得多,因此重复10次大字典可能不是这样。关于记忆的好主意?
**更新** 基于@Giova's answer,我汇总了选项1和2的性能比较,您也可以在repl.it here上找到它们:
from timeit import timeit
def listops(n:int, l):
for i in range(n):
t = l[i]
return l
def dictops(n:int, d):
for i in range(n):
t = d["nice_key_%1d"%i]
return d
n= 10
l = []
for i in range(n):
l.append(i)
d = dict()
for i in range(n):
d["nice_key_%1d"%i] = None
t1=timeit(lambda: listops(n, l), number=1000000)
t2=timeit(lambda: dictops(n, d), number=1000000)
print("list:",t1)
print("dict:",t2)
请注意,这只是查找速度的乘积,而Giova的代码段也着眼于数据结构的创建,而我对此并不感兴趣。
结果:
list: 4.312716690998059
dict: 14.279126501001883
我想回答我问题的“存储空间”部分最简单的方法是同时实现这两个功能并检查泡菜文件的大小?
答案 0 :(得分:2)
在您提到的选项之间,使用字典(2,3)的选项在访问速度方面更好。介于2到3之间的哪个更好,这实际上取决于您希望检索元素的方式。
还可以考虑将逐行数字作为第一个字典的键,通过这样操作,合理地假设字符串比小数字消耗更多的内存,这种技巧将浪费更少的内存。
仅在速度不是很重要的情况下才应考虑选项1。列表方法花费大量时间的原因。只需一个简单的代码片段就可以轻松地凭经验验证这一点:
from elapsed import TimeIt
def listops(n:int):
l = []
for i in range(n):
l.append(i)
for i in range(n):
t = i in l
return l
def dictops(n:int):
d = dict()
for i in range(n):
d[i] = None
for i in range(n):
t = i in d
return d
TimeIt(lambda: listops(10), 1000000, logger_name=__name__, msg='listops(10)')
TimeIt(lambda: dictops(10), 1000000, logger_name=__name__, msg='dictops(10)')
这里,我们有两个函数listops
和'dictops',分别创建给定list
整数的dict
和n
,然后检查每个整数是否存在插入的整数。该代码基本上只希望检查list
和dict
的构造,插入和状态测试。这将注销以下时间:
Elapsed time '1000000 times listops(10)': 3.559521 seconds.
Elapsed time '1000000 times dictops(10)': 2.720709 seconds.
[请注意,TimeIt
(驼峰式保护壳)是我为实现此目的而定制的类,但是您可以从timeit
模块中轻松使用timeit
。]
即使不是您的问题的明确组成部分,我也建议您使用sqlite
内存数据库,并在搜索查询中使用列索引,并准备按需触发准备好的语句。