在 Python 3.6+ 中高效地按位置访问字典项目
Accessing dictionary items by position in Python 3.6+ efficiently
我理解字典是 ,作为 3.6 中的实现细节和 3.7+ 中的官方。
鉴于它们是有序的,似乎很奇怪没有方法可以按插入顺序检索字典的 ith 项。可用的 only solutions 似乎具有 O(n) 复杂性,或者:
- 通过 O(n) 过程转换为列表,然后使用
list.__getitem__
.
enumerate
循环中的字典项和 return 达到所需索引时的值。同样,时间复杂度为 O(n)。
由于从 list
中获取一个项目具有 O(1) 的复杂度,有没有办法用字典实现相同的复杂度?使用常规 dict
或 collections.OrderedDict
都可以。
如果不可能,是否存在阻止这种方法的结构性原因,或者这只是尚未考虑/实施的功能?
对于 OrderedDict
它本质上是 O(n)
因为排序记录在 linked list.
对于内置的dict,有一个向量(一个连续的数组)而不是一个链表,但最后几乎是一样的东西:向量包含一些"dummies",特殊的内部值这意味着 "no key has been stored here yet" 或 "a key used to be stored here but no longer"。这使得,例如,删除一个密钥非常便宜(只需用一个虚拟值覆盖密钥)。
但是如果不在其之上添加辅助数据结构,就无法跳过假人而不一次一个地跳过它们。因为 Python 使用一种开放寻址的形式来解决冲突,并将负载因子保持在 2/3 以下,所以向量的条目中至少有三分之一 是 虚拟对象。 the_vector[i]
可以在 O(1)
时间内访问,但实际上与第 i 个非虚拟条目没有可预测的关系。
根据 ,结构性原因导致您无法在 O(1) 时间内按位置访问字典项目。
如果您正在寻找按键 或 位置的 O(1) 查找,则值得考虑替代方案。 NumPy / Pandas 等第 3 方库提供此类功能,高效 尤其是 对于不需要指针的数字数组。
使用 Pandas,您可以构建一个带有唯一标签的 "dictionary-like" 系列,通过 "label" 或位置提供 O(1) 查找。你牺牲的是删除标签时的性能,这会产生 O(n) 成本,很像 list
.
import pandas as pd
s = pd.Series(list(range(n)))
# O(n) item deletion
del s[i]
s.drop(i)
s.pop(i)
# O(1) lookup by label
s.loc[i]
s.at[i]
s.get(i)
s[i]
# O(1) lookup by position
s.iloc[i]
s.iat[i]
pd.Series
绝不是 dict
的直接替代品。例如,如果该系列主要用作映射,则不会阻止重复键,并且会导致问题。但是,如果数据存储在连续的内存块中,如上例所示,您可能会看到显着的性能改进。
另请参阅:
- What are the advantages of NumPy over regular Python lists?.
- What is the performance impact of non-unique indexes in pandas?
我理解字典是
鉴于它们是有序的,似乎很奇怪没有方法可以按插入顺序检索字典的 ith 项。可用的 only solutions 似乎具有 O(n) 复杂性,或者:
- 通过 O(n) 过程转换为列表,然后使用
list.__getitem__
. enumerate
循环中的字典项和 return 达到所需索引时的值。同样,时间复杂度为 O(n)。
由于从 list
中获取一个项目具有 O(1) 的复杂度,有没有办法用字典实现相同的复杂度?使用常规 dict
或 collections.OrderedDict
都可以。
如果不可能,是否存在阻止这种方法的结构性原因,或者这只是尚未考虑/实施的功能?
对于 OrderedDict
它本质上是 O(n)
因为排序记录在 linked list.
对于内置的dict,有一个向量(一个连续的数组)而不是一个链表,但最后几乎是一样的东西:向量包含一些"dummies",特殊的内部值这意味着 "no key has been stored here yet" 或 "a key used to be stored here but no longer"。这使得,例如,删除一个密钥非常便宜(只需用一个虚拟值覆盖密钥)。
但是如果不在其之上添加辅助数据结构,就无法跳过假人而不一次一个地跳过它们。因为 Python 使用一种开放寻址的形式来解决冲突,并将负载因子保持在 2/3 以下,所以向量的条目中至少有三分之一 是 虚拟对象。 the_vector[i]
可以在 O(1)
时间内访问,但实际上与第 i 个非虚拟条目没有可预测的关系。
根据
如果您正在寻找按键 或 位置的 O(1) 查找,则值得考虑替代方案。 NumPy / Pandas 等第 3 方库提供此类功能,高效 尤其是 对于不需要指针的数字数组。
使用 Pandas,您可以构建一个带有唯一标签的 "dictionary-like" 系列,通过 "label" 或位置提供 O(1) 查找。你牺牲的是删除标签时的性能,这会产生 O(n) 成本,很像 list
.
import pandas as pd
s = pd.Series(list(range(n)))
# O(n) item deletion
del s[i]
s.drop(i)
s.pop(i)
# O(1) lookup by label
s.loc[i]
s.at[i]
s.get(i)
s[i]
# O(1) lookup by position
s.iloc[i]
s.iat[i]
pd.Series
绝不是 dict
的直接替代品。例如,如果该系列主要用作映射,则不会阻止重复键,并且会导致问题。但是,如果数据存储在连续的内存块中,如上例所示,您可能会看到显着的性能改进。
另请参阅:
- What are the advantages of NumPy over regular Python lists?.
- What is the performance impact of non-unique indexes in pandas?