代码之家  ›  专栏  ›  技术社区  ›  jpp

在python 3.6+中按位置高效访问字典项

  •  25
  • jpp  · 技术社区  · 6 年前

    我知道字典是 insertion ordered in Python 3.6+ ,作为3.6和3.7+中的实施细节。

    考虑到它们是有序的,似乎很奇怪,没有任何方法可以检索 按插入顺序排列的字典项。这个 only solutions 可用似乎有O( n )复杂性,或者:

    1. 通过o转换为列表( n )处理然后使用 list.__getitem__ .
    2. enumerate 循环中的字典项,并在达到所需索引时返回值。再次,用O( n )时间复杂性。

    因为从 list 有没有O(1)复杂性,有没有办法用字典来达到同样的复杂性?或者用普通的 dict collections.OrderedDict 会起作用。

    如果不可能的话,是否有结构性原因阻止了这种方法,或者这只是一个尚未被考虑/实现的特性?

    2 回复  |  直到 6 年前
        1
  •  34
  •   Tim Peters    6 年前

    对于一个 OrderedDict 它固有地 O(n) 因为排序记录在 linked list .

    对于内置dict,有一个向量(一个连续数组)而不是一个链表,但最后基本上是一样的:向量包含一些“假人”,特殊的内部值意味着“还没有在这里存储密钥”或“以前在这里存储但现在不再存储的密钥”。这使得,例如,删除一个键非常便宜(只需用一个虚拟值覆盖该键)。

    但是,如果不在上面添加辅助数据结构,就没有办法跳过这些假人,而不逐个跳过它们。因为python使用开放寻址的形式来解决冲突,并且将负载系数保持在2/3以下,至少是向量项的三分之一。 傻瓜。 the_vector[i] 可以在中访问 O(1) 时间,但与第i个非虚拟条目没有可预测的关系。

        2
  •  3
  •   jpp    6 年前

    按照 @TimPeters' answer ,在O(1)时间中,有结构原因无法按位置访问字典项。

    如果您正在寻找O(1)按键查找,则值得考虑其他选项。 位置。有第三方库,如numpy/pandas,提供此类功能、高效 尤其地 对于不需要指针的数值数组。

    使用pandas,您可以构建一个“类似字典”的系列,其唯一标签提供O(1)按“标签”或位置查找。你牺牲的是删除标签时的性能,这会导致( 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 . 例如,如果序列主要用作映射,则不会阻止重复键,并且会导致问题。但是,如果数据存储在一个连续的内存块中,如上面的示例所示,您可能会看到显著的性能改进。

    参见:

    1. What are the advantages of NumPy over regular Python lists? .
    2. What is the performance impact of non-unique indexes in pandas?
    3. Pandas DataFrame search is linear time or constant time?