将字典复制到 defaultdict

Posted

技术标签:

【中文标题】将字典复制到 defaultdict【英文标题】:Copying a dictionary to defaultdict 【发布时间】:2015-11-06 08:06:00 【问题描述】:

我想有效地将​​字典复制到defaultdict。 这是我的代码:

[In]    from collections import defaultdict  
[In]    new_dict = 'a': 1, 'b': 2, 'c': 3, 'e':4, 'f':5  
[In]    def_dict = defaultdict(list)  
[In]    timeit for k, v in new_dict.items(): def_dict[k].append(v)  
[Out]    1000000 loops, best of 3: 910 ns per loop

我想改进它的性能。 欢迎提出任何建议。

【问题讨论】:

如何知道性能何时足够好? @PeterWood 所谓性能,是指运行该函数所花费的时间。 既然您知道def_dict 最初是空的,您可以在for 循环中使用def_dict[k] = [v] Martineau 的建议很好。但不同方法的相对速度取决于new_dict 的大小,Python 2 和 Python 3(以及不同的实现)之间也存在差异。还要记住 Knuth 的话:“大约 97% 的时候说:过早的优化是万恶之源”。 在我的机器上运行 Pytrhon 2.6.6 def_dict[k] = [v] 几乎是 def_dict[k].append(v) 的两倍。另一种选择是使用itertools 中的starmap,例如:def_dict = defaultdict(list, starmap(lambda k, v: (k, [v]), new_dict.items()))。在我的机器上它比append(v) 快,但比= [v] 慢。 【参考方案1】:

我坚持我的建议,即使用 def_dict[k] = [v] 会比 def_dict[k].append(v) 快,根据我自己的测试发现它几乎快两倍。

以下是我用来确定这一点的完整基准代码。我还尝试了其他几种可能性,但没有一个更好。

使用 Python 3.5.0 和 Python 2.7.10 获得了类似的结果。

from __future__ import print_function
import sys
from textwrap import dedent
import timeit

N = 1000000  # number of executions of each "algorithm"
R = 3  # number of Repeations of executions

# common setup for all algorithms (not timed)
setup = dedent("""
    from collections import defaultdict

    new_dict = 'a': 1, 'b': 2, 'c': 3, 'e': 4, 'f': 5
""")

algorithms = 
    "def_dict[k].append(v)": dedent("""
        def_dict = defaultdict(list)
        for k, v in new_dict.items(): def_dict[k].append(v)
    """),

    "def_dict[k] = [v]": dedent("""
        def_dict = defaultdict(list)
        for k, v in new_dict.items(): def_dict[k] = [v]
    """),

    "defaultdict(list, <gen-xprsn>)": dedent("""
        def_dict = defaultdict(list, ((k, [v]) for k, v in new_dict.items()))
        """),

    "defaultdict(list, <dict-comp>)": dedent("""
        def_dict = defaultdict(list, k:[v] for k, v in new_dict.items())
        """),


# collecting results of executing and timing each algorithm snippet
timings = [
    (label,
     min(timeit.repeat(algorithms[label], setup=setup, repeat=R, number=N)),
    ) for label in algorithms
]

# display results
print('fastest to slowest execution speeds (Python ..)\n'.format(
        *sys.version_info[:3]),
        '  (:,d executions, best of :d repetitions)\n'.format(N, R))

longest = max(len(timing[0]) for timing in timings)  # length of longest label
ranked = sorted(timings, key=lambda t: t[1]) # ascending sort by execution time
fastest = ranked[0][1]
for timing in ranked:
    print(":>width : :9.6f secs, rel speed :4.2fx, :6.2f% slower".
            format(timing[0], timing[1], round(timing[1]/fastest, 2),
                   round((timing[1]/fastest - 1) * 100, 2), width=longest))

这是在我的系统上运行的结果:

fastest to slowest execution speeds (Python 3.5.0)
   (1,000,000 executions, best of 3 repetitions)

             def_dict[k] = [v] :  0.977644 secs, rel speed 1.00x,   0.00% slower
defaultdict(list, <dict-comp>) :  1.330040 secs, rel speed 1.36x,  36.05% slower
defaultdict(list, <gen-xprsn>) :  1.761532 secs, rel speed 1.80x,  80.18% slower
         def_dict[k].append(v) :  1.929081 secs, rel speed 1.97x,  97.32% slower

【讨论】:

但是第三个结果会不一样。你不会有列表中的值。 @Peter:好点...不敢相信我错过了。查看更新的答案。

以上是关于将字典复制到 defaultdict的主要内容,如果未能解决你的问题,请参考以下文章

如何将字典键附加到列表中? [复制]

将带有字典列表的 defaultdict(list) 字典转换为 csv 的最佳方法

仅将熊猫值复制到字典:抑制索引 [重复]

如何将键值对添加到字典中? [复制]

如何将关联的相邻熊猫数据框数据导出到字典中? [复制]

如何将字典的值复制到 .Net 2.0 中的 IList 对象中?