Python中的二维字典效率与一维字典效率比较

6
在内存和速度方面,使用d[(first,second)]d[first][second]之间的哪一个更有效率,其中d是元组或字典的字典?

1
第一个是一个字典,第二个是两个。从内存角度来看,两个字典可能会消耗更多的内存 - 但这完全取决于您应用程序的数据配置文件。 - miku
3
我认为答案就是非常微不足道。这里真正的问题应该是:对于使用它的代码读者/编写者来说,什么更易用? - Gareth Latty
2
初音的说法“第一个[语句]是一个字典,第二个[语句]是两个。”并不完全正确。第二个语句d[a][b]实际上是N+1个字典,其中N是a的唯一值的数量。 - ninjagecko
性能在这里是至关重要的,因为更快的执行速度远比代码质量/可读性更重要。 - Zach
2个回答

5

以下是一些非常基本的测试数据,表明对于一个非常牵强附会的示例(使用数字作为键存储“a”一百万次),使用2个字典会显著提高速度。

$ python -m timeit 'd = {i:{j:"a" for j in range(1000)} for i in range(1000)};a = [d[i][j] for j in range(1000) for i in range(1000)];'
10 loops, best of 3: 316 msec per loop
$ python -m timeit 'd = {(i, j):"a" for j in range(1000) for i in range(1000)};a = [d[i, j] for j in range(1000) for i in range(1000)];'
10 loops, best of 3: 970 msec per loop

当然,这些测试并不一定意味着什么,具体取决于您想做什么。请先确定您将要存储的数据,然后进行测试。
以下是更多的数据:
$ python -m timeit 'a = [(hash(i), hash(j)) for i in range(1000) for j in range(1000)]'
10 loops, best of 3: 304 msec per loop
$ python -m timeit 'a = [hash((i, j)) for i in range(1000) for j in range(1000)]'
10 loops, best of 3: 172 msec per loop
$ python -m timeit 'd = {i:{j:"a" for j in range(1000)} for i in range(1000)}'
10 loops, best of 3: 101 msec per loop
$ python -m timeit 'd = {(i, j):"a" for j in range(1000) for i in range(1000)}'
10 loops, best of 3: 645 msec per loop

再次声明,这显然不是真实世界使用的指标,但在我看来,构建一个像这样包含元组的字典的成本是巨大的,这就是为什么字典中嵌套字典会更胜一筹。这让我感到惊讶,我原本期望完全不同的结果。等有时间时,我还需要尝试一些其他方法。


有趣。我猜想差别在于哈希一个“元组”所需的时间增加了? - agf
@agf 发布了更多的数据,我真的不知道为什么差异这么大。使用元组构建字典要昂贵得多,但哈希元组实际上更快?我使用的方法非常粗糙,所以可能读取数据时走得太远了,但我仍然有点困惑。 - Nolen Royalty
我想知道在构建二维字典时逐个循环值是否可以让你缓存更多。这似乎是一个潜在的解释。 - Nolen Royalty
1
请注意,对于仅处理str键的字典,存在一种快速路径;这不会影响算法复杂度,但可以显着影响常数因子:即程序完成的速度。来源也可能会受到影响。 - Gareth Latty

1

有点令人惊讶的是,在CPython 2.7和Pypy 1.8中,字典的字典比元组更快。

我没有检查空间,但你可以用ps来做到这一点。


字典是哈希表,对吧?所以它们当然很快,但它们占用了很多空间。 - mgold
2
什么更快?直觉上,我认为在字典的字典上进行插入会比较慢,因为你通常需要初始化一个新的字典(如果你正在使用一个新的第一个键)。但是,我预计访问速度会更快,因为碰撞数量将少一个数量级。请提供代码,以便我们可以看到您实际上正在进行基准测试的内容。 - Aaron Dufour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接