天天看點

初窺門徑——字典的更好使用方式

字典推導式

清單推導式可能我們已經十分熟悉了,但是其實字典推導式也同樣非常實用。

exam_list = [
    ['alibaba', 'china'],
    ['tencent', 'china'],
    ['orcale', 'america']
]
exam_dict = {compancy:country for compancy,country in exam_list}
exam_dict
           
{'alibaba': 'china', 'tencent': 'china', 'orcale': 'america'}
           

其實使用可以像清單推導一樣靈活,如我們可以把公司名的前三個字母簡稱(并首字母大寫)作為鍵,公司全名作為值。

{'Ali': 'alibaba', 'Ten': 'tencent', 'Orc': 'orcale'}
           

事實上你也很難在其他語言上找到比這更優雅的寫法。

setdefault方法

我覺得這個方法是字典的精髓所在。下面看一個例子。

如我們要進行詞雲的計算操作,我們正常的做法是周遊一遍,求出結果。

for i in company_list:
    if i not in company_dict:
        company_dict[i] = 1
    else:
        company_dict[i] += 1 
company_dict
           
{'alibaba': 3, 'tencent': 1, 'orcale': 2}
           

這是我們的正常處理思路,但我覺得不夠優雅。我們其實可以更簡潔一點。

for i in company_list:
    new_company_dict.setdefault(i, []).append(1)
new_company_dict = {key:sum(value) for key, value in new_company_dict.items()}
new_company_dict
           

這樣是不是更優雅一點,我也不能斷言。但是第一種方法至少要進行三次鍵查詢,而後者則規避了這些。

Counter類

事情上我們在進行上述的計算功能也不用那麼麻煩,Counter類已經為我們做好了一切

from collections import Counter
new_com = Counter(company_list)
new_com
           
Counter({'alibaba': 3, 'tencent': 1, 'orcale': 2})
           

我們也可以把統計好的結果按着從小到大排列

建立有序字典

在說這句話時候,我們已經明确字典是無序的。其實在正常的了解中很多人認為字典是有序的。他的順序就是添加到字典的時間順序。為什麼會這麼認為呢,實際上在windows中字典裡鍵值對的順序往往就是添加到字典中的順序。

但是在linux中往往不是那麼回事,為什麼python字典是無序的下面再講。那麼關于python建立有序字典可以參考我這篇部落格。連結: python 把字典變為有序.

為什麼字典的鍵必須是不可變對象

這個問題想必大家都考慮過,最開始我也想可能因為鍵值對是一一對應,不可變是為了達到這種對應關系。

可是如果兩個清單[1,2,3] 和 [1,2,3,4] 這兩個清單是不同的清單,這種不同的清單也無法作為字典的鍵但是元組卻可以。

這種就比較奇怪了,其實字典是python高度優化的一個結構。因為其實有很多時候,字典會在python中有比較巧妙的運用。

python字典的鍵采用了散清單算法來實作的,所謂的散清單就是哈希表。,它通過把關鍵碼值映射到表中一個位置來通路記錄,以加快查找的速度。這個映射函數叫做[散列函數,存放記錄的數組叫做散清單。

在python字典中是這樣實作高效查詢的,為了擷取 my_dict[search_key] 背後的值,Python 首先會調用 hash(search_key) 來計算 search_key 的散列值,在散清單裡查找表元(具體取幾位,得看 目前散清單的大小)。若找到的表元是空的,則抛出 KeyError 異 常。若不是空的,則表元裡會有一對 found_key:found_value。 這時候 Python 會檢驗 search_key == found_key 是否為真,如 果它們相等的話,就會傳回 found_value。

這也就是python字典的鍵必須是不可變的原因,因為要求他是可哈希的。

為什麼順序會打亂

其實不止dict用的散清單,set同樣如此。dict 和 set 背後的散清單效率很高,對它的了解越深入,就越能了解 為什麼被儲存的元素會呈現出不同的順序,以及已有的元素順序會發生 變化的原因。同時,速度是以犧牲空間為代價而換來的。

随着我們學習的深入,我們發現db為了實作速度的提升建立索引。數倉為了實作資料的提升,使用分區。再到python中的字典和集合,都是犧牲空間來換時間。

正如那句話所說世上安得兩全法。有得到必須得有犧牲。