[英]Accessing dictionary items by position in Python 3.6+ efficiently
我知道字典在 Python 3.6+ 中是按插入順序排列的,作為 3.6 中的實現細節和 3.7+ 中的官方實現細節。
鑒於它們是有序的,似乎沒有方法可以按插入順序檢索字典的第i個項目。 唯一可用的解決方案似乎具有 O( n ) 復雜度,要么:
list.__getitem__
。enumerate
字典項並在達到所需索引時返回值。 同樣,時間復雜度為 O( n )。 由於從list
獲取項目的復雜度為 O(1),有沒有辦法用字典實現相同的復雜度? 使用常規dict
或collections.OrderedDict
都可以。
如果不可能,是否存在阻止這種方法的結構原因,或者這只是尚未考慮/實施的功能?
對於OrderedDict
它本質上是O(n)
因為排序記錄在鏈表中。
對於內置字典,有一個向量(一個連續的數組)而不是一個鏈表,但最后幾乎是一樣的:向量包含一些“啞元”,特殊的內部值,意味着“沒有鍵存儲在這里”或“曾經存儲在這里但不再存儲的密鑰”。 這使得,例如,刪除一個密鑰非常便宜(只需用一個虛擬值覆蓋該密鑰)。
但是,如果不在此基礎上添加輔助數據結構,就無法跳過虛擬對象而不一次一個地跳過它們。 因為 Python 使用一種開放尋址形式來解決沖突,並將負載因子保持在 2/3 以下,所以至少有三分之一的向量條目是虛擬的。 the_vector[i]
可以在O(1)
時間內訪問,但實際上與第 i 個非虛擬條目沒有可預測的關系。
根據@TimPeters 的回答,您無法在 O(1) 時間內按位置訪問字典項存在結構性原因。
如果您正在按鍵或位置尋找 O(1) 查找,則值得考慮替代方案。 有 NumPy / Pandas 等 3rd 方庫提供了這樣的功能,特別是對於不需要指針的數字數組來說非常有效。
使用 Pandas,您可以構建一個具有獨特標簽的“類字典”系列,通過“標簽”或位置提供 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
替代品。 例如,如果該系列主要用作映射,則不會阻止重復鍵並且會導致問題。 但是,如果數據存儲在連續的內存塊中,如上例所示,您可能會看到顯着的性能改進。
也可以看看:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.