【问题标题】:Fastest way to convert Python List with dictionaries to one dictionary将带有字典的 Python 列表转换为一本字典的最快方法
【发布时间】:2015-03-17 03:05:25
【问题描述】:

我已将大量数据解析为包含字典的列表。

[{123123:[0.45, 0.4]},{2332:[0.1, 09]}]

我在这个列表中有近 800,000 条记录,我想从中取出一本字典:

my_dict = {}
for i in dict_list:
    for k,v in i.iteritems():
        my_dict[k] = v

有没有更快的方法来做到这一点。

【问题讨论】:

  • 您可能会通过更改数据解析方式获得更好的收益。如果您从一开始就正确格式化数据,则无需执行任何操作。
  • 每个字典中平均有多少个键?

标签: python python-2.7 dictionary


【解决方案1】:

像这样使用字典理解

>>> dict_list = [{123123:[0.45, 0.4]},{2332:[0.1, 9]}]
>>> {key: item[key] for item in dict_list for key in item}
{123123: [0.45, 0.4], 2332: [0.1, 9]}

由于理解是用 C 代码完成的,它应该比用 Python 迭代和改变字典对象要快。

【讨论】:

  • 在 OP 的代码中更新 my_dict 应该更快,因为它删除了 Python for 循环。
  • 我不知道还有“dict理解”。很高兴知道!! :)
  • 虽然请注意这不考虑重复键。或者更确切地说,它遵循 LIFO 语义;最后遇到的重复键的值将是该键的值。如果这是一种可能性/问题,您将需要一个更复杂的解决方案。
【解决方案2】:

使用更新应该非常有效:

my_dict = {}
for d in dict_list:
    my_dict.update(d)

您输入的一些时间安排:

In [13]: %%timeit
my_dict = {}
for d in dict_list:
    my_dict.update(d)
   ....: 
1000000 loops, best of 3: 557 ns per loop

In [14]: timeit {key: item[key] for item in dict_list for key in item}
1000000 loops, best of 3: 597 ns per loop

In [15]: %%timeit                                         
my_dict = {}
for i in dict_list:
    for k,v in i.iteritems():
        my_dict[k] = v
   ....: 
1000000 loops, best of 3: 664 ns per loop
In [16]: %%timeit
my_dict = {}
for d in dict_list:
    for k in d:
       my_dict[k] = d[k]
   ....: 
1000000 loops, best of 3: 626 ns per loop
In [17]: timeit dict(reduce(operator.add, [dic.items() for dic in  dict_list]))
1000000 loops, best of 3: 1.55 µs per loop

需要注意的一点是,如果您有重复的键,那么您最终将覆盖该值,每次都会以您遇到的特定键的最后一个值结束。

使用包含唯一键的 800000 个字典列表再次运行测试,它显示字典理解是最快的:

In [81]: dict_list = [{i:[1,2,3]} for i in xrange(800000)] 

In [82]: timeit {key: item[key] for item in dict_list for key in item} 
10 loops, best of 3: 165 ms per loop

In [83]: %%timeit                                                      
my_dict = {}
for d in dict_list:
    my_dict.update(d)
   ....: 
1 loops, best of 3: 215 ms per loop

In [84]: %%timeit
my_dict = {}
for d in dict_list:
    for k in d:
       my_dict[k] = d[k]
   ....: 
10 loops, best of 3: 198 ms per loop

In [85]: %%timeit                                                     
my_dict = {}
for i in dict_list:
    for k,v in i.iteritems():
        my_dict[k] = v
   ....: 
1 loops, best of 3: 226 ms per loop

只是为了验证两者产生相同的输出:

In [79]: my_dict = {}                                                 
for d in dict_list:
    my_dict.update(d)
   ....:    
In [115]: len(my_dict)
Out[115]: 2400000


In [80]: my_dict ==  {key: item[key] for item in dict_list for key in item}
Out[80]: True

最终每个字典使用三个键,更新再次获胜:

 In [108]: dict_list = [{i:[1000,2000,3000],i+800000:[1000,2000,3000],i+1700000:[1000,2000,3000]} for i in xrange(800000)]

In [109]: %%timeit
my_dict = {}
for i in dict_list:
    for k,v in i.iteritems():
        my_dict[k] = v
   .....: 
1 loops, best of 3: 468 ms per loop

In [110]: %%timeit
my_dict = {}
for d in dict_list:
    for k in d:              
       my_dict[k] = d[k]
   .....: 
1 loops, best of 3: 476 ms per loop

In [111]: timeit {key: item[key] for item in dict_list for key in item}
1 loops, best of 3: 448 ms per loop

In [112]: %%timeit                                                     
my_dict = {}
for d in dict_list:
    my_dict.update(d)
   .....: 
1 loops, best of 3: 328 ms per loop

所以似乎有更多的键有助于抵消调用更新的成本,所以如果你的输入只有一个键,那么 dict comp 应该更快,如果你有多个键,那么 update 应该是。

【讨论】:

  • 你能把你的简单更新循环与列表推导结合起来吗? IE。 timeit [my_dict.update(dic) for dic dict_list] ?
  • @MarcusMüller, 229 ms 在大型数据集上。以这种方式使用列表组合可能也会不受欢迎;)
  • 惊讶地发现它比“完整”循环慢;我假设列表理解会更快,因为 python 不需要检查范围以进行迭代——很高兴知道!
【解决方案3】:

正如其中一个 cmets 所述,使用dict.update 应该更容易、更快捷:

my_dict = {}
for d in dict_list:
    my_dict.update(d)

【讨论】:

    【解决方案4】:

    reduce 可能仍然可以帮助您(尽管我之前的回答搞砸了):

    import operator
    dict(reduce(operator.add, [dic.items() for dic in dictlist]))
    

    编辑:感谢@padraicCunningham,测试我的东西(并显示它不是那么好,至少对于分离键)

    【讨论】:

      猜你喜欢
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      • 2022-10-06
      • 1970-01-01
      • 2015-07-23
      • 2019-02-10
      • 2016-09-14
      • 2019-11-19
      相关资源
      最近更新 更多