天天看點

一文看懂Python字典類型資料常見操作及排序【工作面試必讀】

Python的字典(dictionary)是一種靈活的資料結構類型,字典的每個鍵值對(key=>value)用冒号(:)分割,每個對之間用逗号(,)分割。Python字典裡的鍵必須獨一無二,但值則不必的。字典的值可以取任何資料類型,但必須是不可變的(unhashable),如字元串,元組或數值, 用清單是不行的。本文教你一文看懂Python字典類型資料常見操作和排序。

一文看懂Python字典類型資料常見操作及排序【工作面試必讀】

字典的建立

字典的建立主要有2種方法: 直接指派和根據鍵指派。下例中分别使用2種方法建立了字典d1和字典d2。

>>> d1 = {'key3': 4, 'key2': 5, 'key1': 4}
>>> print(d1)
{'key3': 4, 'key2': 5, 'key1': 4, }
>>> d2 = dict()
>>> d2['key5']=1
>>> print(d2)
{'key5': 1}
      

通路字典的鍵與值

你可以直接根據dict['鍵名']擷取一個值,也可以通過dict.keys()擷取所有的鍵或者dict.values()擷取所有的值。但需要注意的是dict.keys()或dict.values()傳回的并非清單,你需要使用list方法才能将所有的鍵和值轉化為清單形式。

>>> d1 = {'key3': 4, 'key2': 5, 'key1': 4}
>>> print(d1['key3'])
4
>>> print(d1.keys())
dict_keys(['key3', 'key2', 'key1'])
>>> print(list(d1.keys()))
['key3', 'key2', 'key1']
>>> print(list(d1.values()))
[4, 5, 4]
      

注意: 當你嘗試用一個不存在的鍵擷取值時會出現KeyError,一個更好的習慣是在擷取值前先使用if key in dict來判斷一個鍵是否已經存在。

>>> print(d1['key6'])
Traceback (most recent call last):
  File "<input>", line 1, in <module>
KeyError: 'key6'
>>> print('key6' in d1)
False      

周遊字典

使用for key, value in dict.items()可以周遊整個字典。如果你隻喜歡周遊鍵名或值,你可以隻使用for key in dict.keys()或 for value in dict.values()。

for key, value in d1.items():
    print("{}->{}".format(key, value))

for key in d1.keys():
    print(key)

for value in d1.values():
    print(value)      

字典資料的添加

字典與清單一樣都是可變類型的資料,是以可以實作資料的添加和修改。實作的方法主要有兩種:1是建立新的鍵名并指派,2是使用update方法。dict自帶的update方法非常有用,不僅可以插入新的鍵值對,還是實作兩個字典合并的首選方法。

>>> print(d1)
{'key3': 4, 'key2': 5, 'key1': 4}
>>> d1.update({'key4':2})
>>> print(d1)
{'key3': 4, 'key2': 5, 'key1': 4, 'key4': 2}
>>> d1['key5']=1
>>> print(d1)
{'key3': 4, 'key2': 5, 'key1': 4, 'key4': 2, 'key5': 1}

      

注意: 當建立的鍵名已存在時,dict['鍵名']隻會更新現有值,而不會建立新的鍵值對。

删除字典元素

利用del dict['key']可以删除一個鍵值對,利用del dict可以删除整個字典, 使用dict.clear()方法可以清空一個字典。三者還是有很大差別的。

>>> print(d1)
{'key3': 4, 'key2': 5, 'key1': 4, 'key4': 2, 'key5': 1}
>>> del d1['key5']
>>> print(d1)
{'key3': 4, 'key2': 5, 'key1': 4, 'key4': 2}
>>> d1.clear()
>>> print(d1)
{}
>>> del d1
>>> print(d1)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'd1' is not defined      

利用zip方法由兩個清單建立字典

zip()函數來可以把2個或多個清單合并,并建立一個元組對的清單,使用dict方法可以将其變成字典。元組對的數量以合并清單的最短長度為準。python 3中zip方法合并清單後生成的是zip對象,必需使用dict方法才能将其變成字典。

>>> l1 = [ 1, 2, 3 ]
>>> l2 = [ 'x', 'y', 'z']
>>> l3 = [ 'x', 'y' ]
>>> zip(l1, l2)
<zip object at 0x031D6828>
>>> print(list(zip(l1, l2)))
[(1, 'x'), (2, 'y'), (3, 'z')]
>>> print(list(zip(l1, l3)))
[(1, 'x'), (2, 'y')]
>>> print(dict(zip(l1,l3)))
{1: 'x', 2: 'y'}      

實際上zip方法支援所有可疊代對象(字元串、清單、元祖、字典), 而不僅僅是清單。利用這個特性,我們可以很容易建立各種字典,包括很複雜的字典。我們來看下面2個經典例子。注意zip對象支援直接周遊哦,不需要先轉成list或dict哦。

>> > l1 = [1, 2, 3]
>> > str1 = "abc"
>> > print(dict(zip(l1, str1)))
{1: 'a', 2: 'b', 3: 'c'}
>> > name = ["John", "Jim", "Lucy"]
>> > year = [1983, 1985, 1995]
>> > birth_year = dict(zip(name, year))
>> > print(birth_year)
{'John': 1983, 'Jim': 1985, 'Lucy': 1995}
>> > for name, year in zip(name, year):
    print("{} - {}".format(name, year))

John - 1983
Jim - 1985
Lucy - 1995      

利用zip方法實作鍵值反轉

前文提到zip方法支援所有可疊代對象,也自然支援dict.values()和dict.keys(),利用這個特性我們可以快速實作一個字典的鍵值反轉,如下所示:

>>> d1 = {'key3': 4, 'key2': 5, 'key1': 4, 'key4': 2, }
>>> d2 = dict(zip(d1.values(), d1.keys()))
>>> print(d2)
{4: 'key1', 5: 'key2', 2: 'key4'}      

為什麼使用zip方法後字典少了一個鍵? 還記得我們之前提到過鍵名必需唯一嗎? 可見zip方法對字典資料進行反轉必需考慮值相同而導緻資料丢失的問題。

單個字典根據鍵名或值排序

使用sorted方法可以對單個字典的鍵名進行正向或逆向排序(reverse=True),得到是一個排過序的鍵名清單。然後我們通過使用for key in sorted(d)周遊排過序的鍵進而得到排過序的值。

>>> d1 = {'key3': 4, 'key2': 5, 'key1': 4, 'key4': 2, }
>>> d3 = sorted(d1)
>>> print(d3)
['key1', 'key2', 'key3', 'key4']
>>> print(sorted(d1, reverse=True))
['key4', 'key3', 'key2', 'key1']

>>> for key in sorted(d1):
    print(d1[key])
4
5
4
2      

如果我們希望根據值來排序,我們一般有2種方法: 1. 利用zip方法建構鍵值反轉字典再排序。2. 使用匿名函數lambda。方法2通常是一種更好的方法。

方法1: 使用zip方法反轉字典

>>> d1 = {'key3': 4, 'key2': 5, 'key1': 4, 'key4': 2, }
>>> d2 = dict(zip(d1.values(), d1.keys()))
>>> print(list(d2.keys()))
[4, 5, 2]
>>> for key in sorted(d2):
    print(d2[key])

key4
key1
key2      

由于使用zip方法導緻了數值的缺失,一個更好的方法是使用lambda函數指定key來排序。

方法2: 使用lambda匿名函數

該方法設定排序的key為d1[k], 即每個鍵值對的值來排序。

>>> d1 = {'key3': 4, 'key2': 5, 'key1': 4, 'key4': 2, }
>>> d2 = sorted(d1, key=lambda k: d1[k])
>>> print(d2)
['key4', 'key3', 'key1', 'key2']
>>> for key in d2:
        print(d1[key])

2
4
4
5      

關于lambda函數更多見一文看懂Python清單表達式及高階函數如lambda, zip, enumerate, map和filter方法。

字典的運算

假設我們有如下兩個字典,我們能實作直接相加或相減嗎? 答案是不能。Python 3并不支援字典的直接相加或相減。如果你要合并兩個字典,需要使用dict.update()方法。

>>> d1 = {'key1':1, 'key2':7}
>>> d2 = {'key1':3, 'key3':4}      

雖然python不支援加減運算,但支援針對keys()和values()類似集合的運算, 可以用來求同求異,代碼如下所示:

>>> d1.keys() & d2.keys()
{'key1'}
>>> d1.keys() - d2.keys()
{'key2'}      

你有沒有發現字典的預設運算一般是針對鍵進行的?

提取字典子集

假設我們有如下一個字典(姓名->分數),我們需要提取分數大于60的鍵值對組成一個新的字典子集,我們應該怎麼辦呢? 

d = {'John':50, 'Mary': 65, 'Kitty':90, 'Tom': 100}      

最好最快的方式就是使用字典推倒表達式,方法如下。該方法工作常用,考試必考,請一定要熟練掌握哦。

>>> d = {'John':50, 'Mary': 65, 'Kitty':90, 'Tom': 100}
>>> sub_d = { key:value for key, value in d.items() if value >= 60 }
>>> print(sub_d)
{'Mary': 65, 'Kitty': 90, 'Tom': 100}      

關于清單表達式更多見一文看懂Python清單表達式及高階函數如lambda, zip, enumerate, map和filter方法。

字典清單的排序

實際應用中更常見的是對字典清單排序,而不是對當個字典的鍵或值進行排序。假設你有一個字典清單,你想根據某個或某幾個字典字段來排序這個清單。這時你需要使用 

operator

 子產品的 

itemgetter

 函數,可以非常容易的排序這樣的資料結構。 假設你從資料庫中檢索出來網站會員資訊清單,并且以下列的資料結構傳回:

rows = [
    {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
    {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
    {'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
    {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}]      

根據任意的字典字段來排序輸入結果行是很容易實作的,代碼示例:

from operator import itemgetter

rows_by_fname = sorted(rows, key=itemgetter('fname'))

print(rows_by_fname)      

代碼的輸出如下。注意該方法傳回的直接排過序的完整字典,而不是排過序的鍵名清單。

[{'fname': 'Big', 'uid': 1004, 'lname': 'Jones'},

{'fname': 'Brian', 'uid': 1003, 'lname': 'Jones'},

{'fname': 'David', 'uid': 1002, 'lname': 'Beazley'},

{'fname': 'John', 'uid': 1001, 'lname': 'Cleese'}]      

itemgetter()

 函數也支援多個 keys,比如下面的代碼

rows_by_lfname = sorted(rows, key=itemgetter('lname','fname'))

print(rows_by_lfname)      

輸出如下:

[{'fname': 'David', 'uid': 1002, 'lname': 'Beazley'},

{'fname': 'John', 'uid': 1001, 'lname': 'Cleese'},

{'fname': 'Big', 'uid': 1004, 'lname': 'Jones'},

{'fname': 'Brian', 'uid': 1003, 'lname': 'Jones'}]      

本節關于字典清單的排序介紹來自python cookbook。

字典清單的去重

假設我們有如下一個字典清單,我們需要實作字典值的去重,即提取所有獨特的值組成一個清單。一個最好的方式就是使用清單表達式。

>>> d1 = [{'key1':2}, {'key1':3}, {'key2': 2}, {'key3':4}]
>>> u_value = set(val for dict in d1 for val in dict.values())
>>> print(list(u_value))
[2, 3, 4]
      

同樣的你可以使用清單表達式提取所有獨特的鍵名組成一個清單。

>>> d1 = [{'key1':2}, {'key1':3}, {'key2': 2}, {'key3':4}]
>>> u_key = set(key for dict in d1 for key in dict.keys())
>>> print(list(u_key))
['key2', 'key3', 'key1']      

關于清單表達式更多見一文看懂Python清單表達式及高階函數如lambda, zip, enumerate, map和filter方法。

小結

本文總結了Python字典類型資料常見操作(如建立,添加,修改和删除), 還重點講解了字典和字典清單的排序和去重。如果喜歡本文就點贊吧。如果對Python基礎感興趣,也歡迎閱讀我們的一文看懂Python系列原創文章。

  • 一文看懂Python面向對象程式設計(Python學習與新手入門必看)-絕對原創
  • 一文看懂Python對檔案和檔案夾的操作: 含os, shutil和glob子產品。Python學習面試必讀。
  • 一文看懂Python清單表達式及高階函數如lambda, zip, enumerate, map和filter方法。
  • 一文看懂Python及Django不同類型資料的json序列化(面試工作必讀)
  • 一文看懂Python多程序與多線程程式設計(工作學習面試必讀)
  • 一文看懂Python的8大主要應用領域,看看哪個是你的菜?
  • 一文看懂Python Web開發常見資料庫MangoDB, Memcached和Redis

大江狗

2018.11.6

一文看懂Python字典類型資料常見操作及排序【工作面試必讀】