從字典值中獲取第一個值的最快和最好的方法是什么?有多種技術,但什么是最好的(記憶體和速度),為什么?
下面的例子。我也會感謝其他技術:
dictis = {
1: "One"
, 2: "Two"
, 3: "Three"
, 4: "Four"
}
# 1 technique:
#----------------
value = next(iter(dictis.values()))
print(value)
# 2 technique:
#----------------
value = list(dictis.values())[0]
print(value)
# 3 technique:
#----------------
value = [value for value in dictis.values()][0]
print(value)
# 4 technique:
#----------------
value = next(value for value in dictis.values())
print(value)
uj5u.com熱心網友回復:
TL; 博士
使用第一種方式!對于大型詞典,它比第四種快 2.5 倍,比第二種快 10000 倍,比第三種快 20000 倍。第二種和第三種方式創建完整串列并消耗 O(n) 記憶體
時間測量
對于小詞典:
size = 10
dictis = {i: str(i) for i in range(size)}
code1 = "value = next(iter(dictis.values()))"
code2 = "value = list(dictis.values())[0]"
code3 = "value = [value for value in dictis.values()][0]"
code4 = "value = next(value for value in dictis.values())"
kw = {"number": 1000000, "globals": globals()}
print("code1: ", timeit.timeit(code1, **kw)) # 0.15313154199999998
print("code2: ", timeit.timeit(code2, **kw)) # 0.25568722099999996
print("code3: ", timeit.timeit(code3, **kw)) # 0.49292356800000003
print("code4: ", timeit.timeit(code4, **kw)) # 0.43500832200000006
讓我們檢查一下size = 1_000_000。第二種和第三種方法持續時間很長 ( number = 100)
code1: 1.7961999999982492e-05
code2: 1.607245366
code3: 3.3421025739999997
code4: 6.061599999984679e-05
而對于number = 10_000_00:
code1: 1.7192588249999998
code4: 4.457956223
uj5u.com熱心網友回復:
讓我們解決一些問題。首先,Python 詞典并不總是按標準排序,這取決于版本。在實作方面,它們在 Python 3.5 之前具有任意順序,這意味著list(dictis)如果在中間時間對字典進行了更改,在不同時間進行的相同呼叫可能會回傳順序不一致的串列。所以不要在 3.5 或更低版本中這樣做。Python實際上有幾種不同的實作方式,最常見的是CPython,而另一種流行的是PyPy。在這兩種情況下,字典都是以保留插入順序的方式實作的。CPython 從 3.6 開始就是這樣。請記住:字典的順序只是元素插入的順序,與元素的屬性無關。
其次,“O(n)”和“O(1)”指的是big-O表示法,它是漸進表示法主題中的一個主題。有關于這些的維基百科文章,但它們可能非常技術性。我建議從演算法教科書中閱讀它,比如 Cormen 的。要點是:括號內的數字代表您希望演算法采取多少步驟的“乘數”。如果您希望n至少遍歷專案串列中的每個專案一次,則您的演算法是“O(n)”(昵稱“線性時間”)。如果您只希望查看 1 或 2 個或任意數量的固定且永遠不會改變的專案,那么您就是“O(1)”(昵稱“恒定時間”)。正如 khelwood 對您的問題的評論,第一個選項是 O(1)。iternext方法一次只查看一個元素。我不知道CPython(3.6到3.10)中字典迭代器的實際實作是O(1),但理論上應該是。技術2和技術3將字典轉換為串列,這意味著它們必須訪問每個元素,因此必然要采取更多步驟。技巧 4 使用生成器來實作與技巧 1 類似的效果,但考慮起來更復雜,靈活性較差。
盡管如此,技術 1 和 4 仍使用該函式values來獲取字典值的“視圖”。我不知道這背后有多少作業(據我所知,它可能是 O(n)),所以我認為我們應該切斷中間人。這應該是一個更好的解決方案:
key = next(iter(dictis)) # this doesn't ask to generate a view object
value = dictis[key] # this is instant look-up
我做了一些測驗,這個解決方案實際上與技術 1 相當,因此生成字典值的視圖似乎不需要太多開銷。使用與 kosciej16 的答案相同的測驗size = 1_000_000,number = 10_000以及
code5 = '''
key = next(iter(dictis))
value = dictis[key]
'''
我有
>>> print("code1: ", timeit.timeit(code1, **kw))
code1: 0.002648300000146264
>>> print("code4: ", timeit.timeit(code4, **kw))
code4: 0.0054308000001128676
>>> print("code5: ", timeit.timeit(code5, **kw))
code5: 0.0028101000000333443
但是我可以提供一個更好的解決方案,但這需要更多的作業嗎?如果您想跟蹤元素插入到集合中的順序,您會從使用佇列中受益匪淺。您可以在演算法教科書中查找詳細資訊。基本上它是一種資料結構,用于跟蹤插入事物的順序。您可能必須將資料存盤在物件中,這在記憶體方面的成本更高。
class Objectis():
def __init__(self, id, data):
self.id = id
self.data = data
然后制作一堆這些物品:
item1 = Objectis(1, "One")
item2 = Objectis(2, "Two")
item3 = Objectis(3, "Three")
item4 = Objectis(4, "Four")
以任何順序將它們添加到串列中:
queue = [] # you should start your queue empty
queue.append(item3)
queue.append(item1)
queue.append(item2)
queue.append(item4)
如果您想知道誰是第一個,您可以立即使用queue[0]. 如果你想知道誰是最后一個就做queue[-1]。如果要洗掉第一個元素,可以執行element = queue.pop(0). 如果你想在第一個位置插入一個元素,你可以這樣做queue.insert(0, element)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/394119.html
上一篇:正則運算式
