【问题标题】:What is efficiency of key=dictionary.get?key=dictionary.get 的效率是多少?
【发布时间】:2020-08-21 12:45:44
【问题描述】:

我有一本字典,我想找到一种优雅而有效的方法来找到一个 key:value 对,其中字典中的值最小(如果存在很多,则为最小值之一)。除了明显的 for 循环方法外,我还在 StackOverflow 中找到了其他几种方法:

第一种方法:

  temporary = [x for x in myDictionary.items()] # list is created just for using sorted()
  foundKey, minimalValue = sorted(temporary, key=lambda x: x[1]) [0]

第二种方法:

  minimalValue = min(myDictionary.values())
  foundKey = min(myDictionary, key=myDictionary.get)

对于 myDictionary 的数千个项目,第二个运行得稍微快一些,但是......我找不到 key=myDictionary.get 构造的解释。不是可以将两分钟合二为一吗foundKey, minimalValue = ...

【问题讨论】:

  • 为什么不使用foundKey, minimalValue = min(myDictionary.items(), key = lambda x:x[1])之类的东西?
  • 在我编辑我的问题并找到你的答案的同时,对我的建议很好!无论如何, 'key=myDictionary.get' 中的 'get' 是什么?我只知道 'get()' 方法。
  • @mja。您仍然可以考虑通过单击旁边的复选标记来选择我的答案,或者发布您自己的答案并选择它。无论哪种方式,选择答案都会将您的问题从未回答队列中删除。
  • @mja。我在回答中添加了一些时间。看起来像__getitem__,因为您的密钥是最快的方法。享受吧。

标签: python python-3.x dictionary min


【解决方案1】:

第二种方法可以更好地改写为

foundKey = min(myDictionary, key=myDictionary.get)
minValue = myDictionary[foundKey]

get 方法检索与正在检查的键对应的值,因此您不是比较 key1key2,而是比较 myDictionary.get[key1]myDictionary.get[key2]

您同样可以使用__getitem__。它可能会更快,但看起来不会那么漂亮:

foundKey = min(myDictionary, key=myDictionary.__getitem__)

顺便说一下,第一种方法有两个可能的改进:

temporary = list(myDictionary.items())
foundKey, minimalValue = sorted(temporary, key=lambda x: x[1])[0]

temporary = [x[::-1] for x in myDictionary.items()]
foundKey, minimalValue = min(temporary)

foundKey, minimalValue = min(zip(myDictionary.values(), myDictionary.keys()))

时机

让我们制作一个大小为n的字典:

from random import shuffle

values = list(range(n))
shuffle(values)
myDictionary = dict(zip(map('{:08d}'.format, range(n)), values))

n=10000 的时间安排:

%%timeit
... temporary = [x for x in myDictionary.items()]
... foundKey, minimalValue = sorted(temporary, key=lambda x: x[1])[0]
5.76 ms ± 32.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
... minimalValue = min(myDictionary.values())
... foundKey = min(myDictionary, key=myDictionary.get)
1.85 ms ± 3.57 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

很明显,运行 min (O(n)) 比 sorted (O(n log n)) 快。

%%timeit
... foundKey = min(myDictionary, key=myDictionary.get)
... minValue = myDictionary[foundKey]
1.36 ms ± 10.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

所以运行min 并进行查找比运行min 两次要快。

%timeit foundKey, minimalValue = min(zip(myDictionary.values(), myDictionary.keys()))
1.32 ms ± 6.82 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

在没有查找的情况下运行 min 会更快。

%%timeit
... foundKey = min(myDictionary, key=myDictionary.__getitem__)
... minValue = myDictionary[foundKey]
1.27 ms ± 2.77 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

使用__getitem__ 进行查找更快。

TL;DR

似乎这里显示的最快方法是

foundKey = min(myDictionary, key=myDictionary.__getitem__)
minValue = myDictionary[foundKey]

【讨论】:

  • 感谢您的建议!我在我的完整项目中进行了类似的测量,结果相似:您最快的方法需要 48 秒,而使用 get 代替 __getitem__ 的类似方法需要 52 秒(每次 4 分之二)。我最终选择了get,因为它对我来说更好看(因为我已经理解了它的含义)——我今年 72 岁,绝对是编程初学者;)
  • @mja。永远不会太晚,而且您肯定有正确的方法。我希望更多的人只是为自己的项目进行基准测试。顺便说一句,dunder(双下划线的缩写)方法实现了 Python 对象的运算符。 __getitem__ 是字典和列表使用的[...] 索引运算符。 get__getitem__ 之间的最大区别在于,一个返回 None,另一个在缺少键名时引发 KeyError
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-24
  • 2011-01-18
  • 1970-01-01
  • 1970-01-01
  • 2013-06-11
  • 1970-01-01
相关资源
最近更新 更多