对python 3.7+;词典

对python 3.7+;词典,python,performance,dictionary,python-3.7,Python,Performance,Dictionary,Python 3.7,现在,从Python3.7(and)开始,按值和键对字典排序的最佳/最快方法是什么 最明显的方法可能是: by_key = {k: dct[k] for k in sorted(dct.keys())} by_value = {k: dct[k] for k in sorted(dct.keys(), key=dct.__getitem__)} 有没有其他更快的方法来实现这一点 请注意,这个问题不是重复的,因为以前关于如何对词典排序的问题已经过时(答案基本上是,您不能;请改用collectio

现在,从Python3.7(and)开始,按值和键对字典排序的最佳/最快方法是什么

最明显的方法可能是:

by_key = {k: dct[k] for k in sorted(dct.keys())}
by_value = {k: dct[k] for k in sorted(dct.keys(), key=dct.__getitem__)}
有没有其他更快的方法来实现这一点

请注意,这个问题不是重复的,因为以前关于如何对词典排序的问题已经过时(答案基本上是,您不能;请改用
collections.OrderedDict
);DR:在CPython 3.7中,按键或按值(分别)排序的最佳方法:
在带有系统版本的macbook上测试:

3.7.0b4 (v3.7.0b4:eb96c37699, May  2 2018, 04:13:13)
[Clang 6.0 (clang-600.0.57)]
dict为1000个浮点数的一次性设置:

>>> import random
>>> random.seed(123)
>>> d = {random.random(): random.random() for i in range(1000)}
按键对数字进行排序(从最佳到最差):

按值对数字进行排序(从最佳到最差):

使用大量字符串进行一次性设置:

>>> import random
>>> from pathlib import Path
>>> from operator import itemgetter
>>> random.seed(456)
>>> words = Path('/usr/share/dict/words').read_text().splitlines()
>>> random.shuffle(words)
>>> keys = words.copy()
>>> random.shuffle(words)
>>> values = words.copy()
>>> d = dict(zip(keys, values))
>>> list(d.items())[:5]
[('ragman', 'polemoscope'),
 ('fenite', 'anaesthetically'),
 ('pycnidiophore', 'Colubridae'),
 ('propagate', 'premiss'),
 ('postponable', 'Eriglossa')]
>>> len(d)
235886
按键对字符串的dict排序:

>>> %timeit {k: d[k] for k in sorted(d)}
# 387 ms ± 1.98 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: d[k] for k in sorted(d.keys())}
# 387 ms ± 2.87 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit dict(sorted(d.items(), key=itemgetter(0)))
# 461 ms ± 1.61 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit dict(sorted(d.items(), key=lambda kv: kv[0]))
# 466 ms ± 2.62 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: v for k,v in sorted(d.items(), key=itemgetter(0))}
# 488 ms ± 10.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: v for k,v in sorted(d.items(), key=lambda kv: kv[0])}
# 536 ms ± 16.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit dict(sorted(d.items()))
# 661 ms ± 9.09 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: v for k,v in sorted(d.items())}
# 687 ms ± 5.38 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
按值对字符串的dict排序:

>>> %timeit {k: v for k,v in sorted(d.items(), key=itemgetter(1))}
# 468 ms ± 5.74 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit dict(sorted(d.items(), key=itemgetter(1)))
# 473 ms ± 2.52 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit dict(sorted(d.items(), key=lambda kv: kv[1]))
# 492 ms ± 9.06 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: v for k,v in sorted(d.items(), key=lambda kv: kv[1])}
# 496 ms ± 1.87 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: d[k] for k in sorted(d, key=d.__getitem__)}
# 533 ms ± 5.33 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: d[k] for k in sorted(d, key=d.get)}
# 544 ms ± 6.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: d[k] for k in sorted(d, key=lambda k: d[k])}
# 566 ms ± 5.77 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

注意:现实世界的数据通常包含已排序序列的长序列,Timsort算法可以利用这些序列。如果对dict进行排序的速度很快,那么建议在得出关于最佳方法的任何结论之前,使用自己的典型数据在自己的平台上进行基准测试。每次生成结果时,我都会预先添加一个注释字符(
#
),这样IPython用户就可以复制/粘贴整个代码块,以便在自己的平台上重新运行所有测试。

这将相当于分析同一代码的一系列版本。比如,当你可以做
{k:v
并用
items()
代替
keys()
时,为什么要偏爱
{k:dct[k]…
。by值是一样的,但是使用
操作符。itemgetter(1)
作为键。@g.d.c我认为你所说的可能是这样的(因此这个问题很无聊)但我想我还是会问,因为可能有一种我不知道的有趣的开箱即用的方式。由于这是一种非常新的方式,我假设正确的习惯用法尚未建立。Fair.IMHO,我只是等待社区向底层dictionary类添加排序方法(现在它们已经排序)我敢打赌,您会看到类似于
def sort(byValues=False)
,因此默认情况下它会按键排序,但通过类似于
sort(True)
的调用,您会得到按值排序(或类似于这些行的内容)@g.d.d.c我想你是对的。一个不能就地排序的易变有序的东西感觉像是一个反模式。按键排序的最少代码是
dict(sorted(dct.items())
对于按键对数字进行排序,我始终得到相似的结果,但对于按值对数字进行排序,结果不同。非常好的计时分析。因此,一些关键的观察结果似乎是:
dict
比dict理解快,但是元组上的分界比使用键函数仅比较键的成本更高,因此,使用
itemgetter
比lambda快。(也就是说,仔细观察,尤其是对于按值排序,
dict
似乎比dict-coprehension慢…)我认为这真的会从某种视觉/表格概述中受益。我看得越久,它的意义就越小……使用
itemgetter
,dict和dict comp之间的差异是15µs,其他都是一样的,但使用
lambda
它是40µs。而按值排序,
dict
比bo慢太长了,读不下去了。你知道吗?这是一个很相似的结果。时间看起来相当相似,毫无疑问,这取决于数据的细节和用于测试的系统,TL也是如此;DR结论是保证的?<代码> DICT(排序(D项()))<代码>感觉更习惯。
>>> import random
>>> from pathlib import Path
>>> from operator import itemgetter
>>> random.seed(456)
>>> words = Path('/usr/share/dict/words').read_text().splitlines()
>>> random.shuffle(words)
>>> keys = words.copy()
>>> random.shuffle(words)
>>> values = words.copy()
>>> d = dict(zip(keys, values))
>>> list(d.items())[:5]
[('ragman', 'polemoscope'),
 ('fenite', 'anaesthetically'),
 ('pycnidiophore', 'Colubridae'),
 ('propagate', 'premiss'),
 ('postponable', 'Eriglossa')]
>>> len(d)
235886
>>> %timeit {k: d[k] for k in sorted(d)}
# 387 ms ± 1.98 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: d[k] for k in sorted(d.keys())}
# 387 ms ± 2.87 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit dict(sorted(d.items(), key=itemgetter(0)))
# 461 ms ± 1.61 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit dict(sorted(d.items(), key=lambda kv: kv[0]))
# 466 ms ± 2.62 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: v for k,v in sorted(d.items(), key=itemgetter(0))}
# 488 ms ± 10.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: v for k,v in sorted(d.items(), key=lambda kv: kv[0])}
# 536 ms ± 16.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit dict(sorted(d.items()))
# 661 ms ± 9.09 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: v for k,v in sorted(d.items())}
# 687 ms ± 5.38 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: v for k,v in sorted(d.items(), key=itemgetter(1))}
# 468 ms ± 5.74 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit dict(sorted(d.items(), key=itemgetter(1)))
# 473 ms ± 2.52 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit dict(sorted(d.items(), key=lambda kv: kv[1]))
# 492 ms ± 9.06 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: v for k,v in sorted(d.items(), key=lambda kv: kv[1])}
# 496 ms ± 1.87 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: d[k] for k in sorted(d, key=d.__getitem__)}
# 533 ms ± 5.33 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: d[k] for k in sorted(d, key=d.get)}
# 544 ms ± 6.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit {k: d[k] for k in sorted(d, key=lambda k: d[k])}
# 566 ms ± 5.77 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)