與字典值有關(guān)的計算 問題 想對字典的值進行相關(guān)計算,例如找出字典里對應(yīng)值最大(最?。┑捻?。 解決方案一: 假設(shè)要從字典 {'a':3, 'b':2, 'c':6} 中找出值最小的項,可以這樣做: >>> d = {'a':3, 'b':2, 'c':6}>>> min(zip(d.values(), d.keys()))(2, 'b') 值得注意的是 d.values() 獲取字典的全部值,d.keys() 獲取字典的全部鍵,而且兩個序列的順序依然保持一一對應(yīng)的關(guān)系。因此 zip(d.values(), d.keys()) 實質(zhì)上生成的是一個 (value, key) 的序列。min 函數(shù)通過比較序列中的元組 (value, key) 找出其最小值。 解決方案二: 除了使用 zip(d.values(), d.keys()) 外,還可以使用 dict.items() 方法和生成器推導(dǎo)式來生成 (value, key) 序列,從而傳遞給 min 函數(shù)進行比較: >>> d = {'a':3, 'b':2, 'c':6}>>> min((v ,k) for (k, v) in d.items())(2, 'b') 這里 min 函數(shù)的參數(shù) (v ,k) for (k, v) in d.items() 其實是一個生成器推導(dǎo)式(和列表推導(dǎo)式一樣,只是把列表推導(dǎo)式的 [] 改為 () ,而且其返回的一個生成器而非列表),由于生成器推導(dǎo)式做為 min 函數(shù)的參數(shù),所以可以省略掉兩邊的括號(不做為參數(shù)時寫法應(yīng)該是 ((v ,k) for (k, v) in d.items()) )。 字典推導(dǎo)式 問題 想把一個元組列表轉(zhuǎn)換成一個字典,例如把 [('a', 1), ('b', 2), ('c', 3)] 轉(zhuǎn)化為 {'a': 1, 'b': 2, 'c': 3} 解決方案 類似于列表推導(dǎo)式,字典推導(dǎo)式可以方便地從其他數(shù)據(jù)結(jié)構(gòu)構(gòu)造字典,例如: >>> l = [('a', 1), ('b', 2), ('c', 3)]>>> {k: v for k, v in l}{'c': 3, 'b': 2, 'a': 1} 字典推導(dǎo)式的規(guī)則和列表推導(dǎo)式一樣,只是把 [] 換成 {} 尋找字典的交集 問題 假設(shè)有兩個字典: d1 = {'a':1, 'b':2, 'c':3, 'd':4}d2 = {'b':2, 'c':3, 'd':3, 'e':5} 要找出這兩個字典中具有公共鍵的項,即要得到結(jié)果 {'b':2, 'c':3} 解決方案 我們知道一般通過 d.items() 方法來遍歷字典,d.items() 方法返回的對象是一個類集合對象,支持集合的基本運算,如取交集、并集等。 >>> dict(d1.items() & d2.items()) # 取交集{'b': 2, 'c': 3} 此外,d.keys() 返回字典的鍵,也是一個類集合對象,如果我們只想找出兩個字典中鍵相同的項,可以這樣: >>> { k:d1[k] for k in d1.keys() & d2.keys() }{'b': 2, 'd': 4, 'c': 3} 這里如果相同的鍵對應(yīng)不同的值則去第一個字典中的值。推廣開來,如果想排除掉字典中的某些鍵,可以這樣: >>> { k:d1[k] for k in d1.keys() - {'c', 'd'} } # - 號的含義是集合的差集操作{'b': 2, 'a': 1} 但有一點需要注意的是,d.values() 返回字典的值,由于字典對應(yīng)的值不一定唯一,所以 d.values() 一般無法構(gòu)成一個集合,因此也就不支持一般的集合操作。 多個字典連接成一個字典 問題 有多個字典,例如: d1 = {'a':1, 'b':2, 'c':3}d2 = {'c':4, 'd':5, 'e':6} 想將這多個字典連接為一個字典,或一次性對多個字典進行迭代操作。 解決方案 使用 collections.ChainMap : >>> from collections import ChainMap>>> chain_dict = ChainMap(d1, d2)>>> for k, v in chain_dict.items(): print(k, v)a 1e 6d 5c 3b 2 ChainMap 將傳入的多個字典連接為一個字典,并返回一個 ChainMap 對象,這個對象的行為就像一個單一的字典,我們可以對其進行取值或者迭代等操作。注意到這里鍵 c 對應(yīng)的值為 3,如果傳入 ChainMap 的字典含有相同的鍵,則對應(yīng)的值為先傳入的字典中的值。 此外,如果你只想單純地迭代字典的鍵值對,可以結(jié)合使用 items() 和 itertools.chain() 方法: >>> from itertools import chain>>> for k, v in chain(d1.items(), d2.items()): print(k, v)a 1c 3b 2e 6c 4d 5 這里相同的鍵會被分別迭代出來。 保持字典有序 問題 想讓字典中元素的迭代順序和其加入字典的順序保持一致 解決方案 通常來說,使用 d.items() 或者 d.keys()、d.values() 方法迭代出來的元素順序是無法預(yù)料的。例如對字典 d = {'a':1, 'b':2, 'c':3} 迭代: >>> d = dict()>>> d['a'] = 1>>> d['b'] = 2>>> d['c'] = 3>>> for k, v in d.items(): print(k, v)a 1c 3b 2 每一次運行結(jié)果都可能不同。如果想讓元素迭代的順序和創(chuàng)建字典時元素的順序一致,就要使用 collections.OrderedDict 代替普通的 dict : >>> from collections import OrderedDict>>> ordered_d = OrderedDict()>>> ordered_d['a'] = 1>>> ordered_d['b'] = 2>>> ordered_d['c'] = 3>>> for k, v in ordered_d.items(): print(k, v) a 1b 2c 3 OrderedDict 實際通過維護一個雙向鏈表來記錄元素添加的順序,因此其耗費的內(nèi)存大約為普通字典的兩倍。所以在實際使用中需綜合考慮各種因素來決定是否使用 OrderedDict 。 使字典的鍵映射多個值 問題 通常情況下字典的鍵只對應(yīng)一個值?,F(xiàn)在想讓一個鍵對應(yīng)多個值。 解決方案 為了使一個鍵對應(yīng)多個值,首先需要把多個值放到一個容器中(例如列表或者集合等)。例如有這樣一個列表:[('a', 1), ('a', 2), ('b', 3), ('b', 4), ('c', 5)] ,我們要將其轉(zhuǎn)換成一個字典,保持元素的鍵值對應(yīng)關(guān)系,通常我們會寫這樣的代碼: >>> from pprint import pprint>>> l = [('a', 1), ('a', 2), ('b', 3), ('b', 4), ('c', 5)]>>> d = {}>>> for k, v in l: if k in d: d[k].append(v) else: d[k] = [v]>>> pprint(d){'a': [1, 2], 'b': [3, 4], 'c': [5]} 但是 if else 語句讓代碼顯得有點冗余和不易讀,Python 的 defaultdict 改善上述代碼。 >>> from collections import defaultdict>>> d = defaultdict(list)>>> for k, v in l: d[k].append(v)>>> pprint(d)defaultdict(<class 'list'>, {'c': [5], 'b': [3, 4], 'a': [1, 2]}) if else 的判語句沒有了。 defaultdict 是 dict 的一個子類。對 dict 來說,如果 key 不存在,則 dict[key] 取值操作會拋出 KeyError 異常,但是 defaultdict 則會返回一個傳入 defaultdict 構(gòu)造器的類的實例(例如一個列表)或者自定義的缺失值。因此在上例中,對于 d[k].append(v) ,當(dāng) k 不存在時,則會先執(zhí)行 d[k] = [] 并返回這個空列表,繼而將 v 加入到列表中。 傳入 defualtdict 構(gòu)造器的值不一定要是一個類,也可以是一個可調(diào)用的函數(shù),當(dāng)相應(yīng)的鍵不在 defualtdict 中時,其默認(rèn)的值就為這個函數(shù)的返回值,例如: >>> from collections import defaultdict>>> def zero_default(): return 0>>> d = defaultdict(zero_default)>>> d['a'] = 1>>> d['a']1>>> d['b']0>>> d.keys()dict_keys(['b', 'a'])>>> 利用這樣一個特性,我們可以構(gòu)造無限深度的字典結(jié)構(gòu): >>> from collections import defaultdict>>> import json>>> tree = lambda: defaultdict(tree)>>> d = tree()>>> d['a']['b'] = 1>>> print(json.dumps(d)) # 為了顯示的格式更好看{'a': {'b': 1}} 這里當(dāng)執(zhí)行 d['a'] 時,由于相應(yīng)的鍵不存在,故返回一個 defaultdict(tree),當(dāng)再執(zhí)行 d['a']['b'] = 1 時,將鍵 b 對應(yīng)的值設(shè)為 1 。 |
|