python - 增加字典中计数器的最快方法

标签 python performance loops dictionary counter

递增存储在字典中的计数器的最快方法是什么?

因为我必须执行相同的操作数十万次,所以我正在寻找比下面的方法更有效的方法:

def funcA(a):
    keys = [x for x in range(1, 51)]
    adict = {key: 0 for key in keys}

    for k in adict.keys():  # this is the code I would like to improve
        if k <= a:
            adict[k] += 1
        else:
            break


import timeit
number = 100000

t1 = timeit.timeit(
        'funcA(5)',
        setup="from __main__ import funcA", number=number)
print(t1)

>>> 0.42629639082588255

尝试使用列表理解似乎会减慢一切,可能是因为它缺少 break声明?

def funcB(a):
    # not working, invalid syntax
    keys = [x for x in range(1, 51)]
    adict = {key: 0 for key in keys}

    def _inc(x):
        x += 1
        return x

    [_inc(adict[k]) for k in adict.keys() if k <= a]

# Timing: 0.5831785711925477

注意:最初我有 if float(k) <= float(a):但因为我只期待数字(整数或 float ),删除 float()转换改进了代码。这个假设合理吗?

注 2:如多条评论所述,break语句可能会在生成的字典中给出意想不到的结果,所以最好只做:

def funcA(a):
    keys = [x for x in range(1, 51)]
    adict = {key: 0 for key in keys}

    for k in adict:
        if k <= a:
            adict[k] += 1

# Timing: 0.5132114209700376

最佳答案

在您的情况下,您可以只使用 bool 值(比较的结果)可以简单地转换为整数这一事实。它可能不是最快的,但绝对短而且“相对”快:

def funcA(a):
     adict = {key: int(key <= a) for key in range(1, 51)}

这是假设第二个函数实际上是您想要的,因为第一个函数可能会因为 break 而给出不同的结果。字典是无序的,因此它不能为小于或等于 a 的键增加一些值。此外,它不会增加值,它只是将它们设置为 10,因为在这种情况下您实际上不需要添加。

但是,这不一定是最快的方法,因为它必须执行大量函数调用和 int 查找。因此,我将按照性能顺序(从最快到最慢)展示一些更等效的操作:

def cached_version():
    range_cache = range(1, 51)
    cache = dict.fromkeys(range_cache, 0)
    def inner(a):
        adict = cache.copy()
        for key in range_cache[:a]:  # requires a to be an integer!
            adict[key] = 1
        return adict
    return inner

func1 = cached_version()  # initialize cache

def func2(a):
    keys = range(1, 51)
    adict = dict.fromkeys(keys[:a], 1)   # requires a to be an integer!
    for key in keys[a:]:
        adict[key] = 0
    return adict

def func3(a):
    adict = {}
    for key in range(1, 51):
        if key <= a:
            adict[key] = 1
        else:
            adict[key] = 0
    return adict

def func4(a):
    return {key: 1 if key <= a else 0 for key in range(1, 51)}

def func5(a):
    keys = range(1, 51) 
    adict = dict.fromkeys(keys[:a], 1)  # requires a to be an integer!
    adict.update(dict.fromkeys(keys[a:], 0))
    return adict

def func6(a):
    return dict(zip(range(1, 51), [1]*a + [0]*(49-a)))  # requires a to be an integer!

from itertools import chain

def func7(a):
    return dict(zip(range(1, 51), chain([1]*a, [0]*(49-a))))  # requires a to be an integer!

def func8(a):  # the one I originally mentioned
     adict = {key: int(key <= a) for key in range(1, 51)}

计时是在 Python 3.5、Windows 10 上完成的,在其他机器和其他 Python 版本上可能存在差异。另请注意,如果您有更多键而不仅仅是 range(1, 51),性能可能会完全不同。

关于python - 增加字典中计数器的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45978839/

相关文章:

python - 将数据添加到现有文件python的末尾

python - 了解如何衡量函数的时间复杂度

jquery选择器性能

performance - JavaFX:List 与 ObservableList 性能/内存使用情况

postgresql - PostgreSQL 中基于游标的记录

python - 查找两列比较之间的唯一字符

python - 有没有办法找到一个字符串中某个标签的所有索引,相对于删除标签的同一个字符串?

performance - 为什么 JSF 多次调用 getter

c++ - 字母输入运行无限循环

java - 在 Java 中迭代列表的方法