2017-12-05

Python Tutorial–Lesson: Dictionaries Data Type 資料型態 - 字典

接下來要介紹 Python 中另一個非常重要的資料型態 dictionary(字典)



學習目標:
◆ Dictionary 字典資料型態介紹
◆ Dictionary 設定與操作
◆ Dictionary 方法與應用

本篇要介紹 Python 中另一個非常重要的資料型態 dictionary(字典),它是一種被廣泛使用的資料結構,可以讓資料在具有 index (索引)的同時,還存在結構,因此我們可以用 dictionary 賦與資料有意義而且容易被了解的結構。各種電腦語言幾乎都會提供(實作) dictionary(字典)這個資料型態以及功能,Python也不例外。 list 和 dictionary 在 Python 裡使用的機會非常高,用途也很強大,您一定要學會它們。
list 我們在另一篇已經介紹過了,list 是一串有序(ordered)的資料,讓我們可以使用順序位置當作索引(index)來存取 list 中的資料(元素),像這樣 myList[0], myList[1:10], myList[5:],但 dictionary 不同,它不是有序的(unordered)。dictionary 的 unordered 特性同樣反應在兩件事上,第一,dictionary 不能直接對資料(元素)進行大小排序;第二,dictionary 不能像 list 用整數的位置當索引去存取資料。那怎麼辦,我們要怎麼存取使用 dictionary 裡的資料(元素)呢?
dictionary 使用「鍵值對(key-value pair)」的結構來定義和存取資料,key(鍵)就是它的索引,value 是 key 對應的值,key 和 value 間用冒號(':', colon)分隔,並以大括號('{}', brace)包起來,像這樣:

myDictionary_1 = {key(鍵):value(值)}
例:myDictionary_1 = {'name':'Jack','age':20}

您可以把 dictionary 的結構想像成一般的字典,字典中的每一個字或詞(就是key,鍵)都對應到一個或一組的意義(就是value,值)。key(鍵)是不可重覆的(unique),就像字典裡不會查到兩個 apple,但可能會有 apple(一種水果)以及 Apple(蘋果公司),這是兩個不同的字(key);而且 key 是不可改變的,就像 apple 這個字絕不會突然變成 applee,那就會是另一個新字。但 Python 的 dictionary 和字典還是有不同的地方,字典裡的字是有順序的,按英文字母的順序排列,讓我們可以用字母順序查詢,但 dictionary 裡的 key 是沒有順序的,也不能像 list 一樣用 sort() 方法排序它。
key(鍵)可以是數值或字串,因為 key 是不可改變的(immutable),因此只含有數值、字串和 tuple 的 tuple 也可以當作 key,但如果 tuple 裡含有 list,就不可以了,因為 tuple 中的 list 是可以改變的。value(值)則可以是任何型態的資料,數值、字串、布林、日期、list、tuple、甚至是另一個 dictionary,這賦與 dictionary 很大的使用彈性。有了對 dictionary 基礎的了解,接下來我們來設定、讀取和改變 dictionary:

# Python dictionary examples  @author: Sean Lu.
myDictionary_1={'name':'Jack','age':20}  # 設定一個 dictionary
print(myDictionary_1['name'])  # 讀取 myDictionary_1 中 key='name' 的值/資料內容(value)
print(myDictionary_1['age'])  # 讀取 myDictionary_1 中 key='age' 的值/資料內容(value)
print(myDictionary_1[0])  # 錯誤,dictionary 不能用位置索引來存取,會導致 KeyError
myDictionary_1['gender']  # 錯誤,不存在的 key,會導致 KeyError
myDictionary_1['age']=21  # 改變 myDictionary_1 中 key='age' 的值/資料內容(value)
print(myDictionary_1)

雖然 dictionary 是用大括號設定宣告,但讀取和使用時還是用中括號([])喔,您會發現使用方式和 list 很接近。那如果要新增或刪除 dictionary 裡的元素/資料要怎麼作呢?

# Python dictionary examples  @author: Sean Lu.
myDictionary_1={'name':'Jack','age':20}  # 設定一個 dictionary
myDictionary_1['gender']='male'  # 加入一組新的元素/資料 key-value pair
myDictionary_1['zodiac']='Pisces'  # 加入一組新的元素/資料 key-value pair
print(myDictionary_1)
del myDictionary_1['gender']  # 刪除 dictionary 元素
print(myDictionary_1)

在 dictionary 裡要增加一組新的 key-value pair,直接給新的 key 和 value 就可以了,不用像 list 使用 append(), extend() 或 (+);而刪除就和 list 一樣用 del,但 dictionary 沒有像 list 的 remove() 方法喔!
您可能會想,那可不可把將 dictionary 的 key 用整數 0, 1, 2, 3, ...那不就和 list 一樣了?沒錯您可以用整數當 key,像下面這個例子,用起來跟 list 很像,連讀取和改變值的方式都一樣。不過 dictionary 沒有位置和順序,因此沒辦法像 list 以 slice 取某個區間的資料出來(區間是有位置和順序意義的)。

# Python dictionary examples  @author: Sean Lu.
# Use integer as key.
myDictionary_3={0:'Jack',1:'Peter',2:'Alice',3:'Ben'}
print(myDictionary_3[0])  # 讀取 myDictionary_3 中 key=0 的值/資料內容(value)
myDictionary_3[1]='Peters'  # 改變 myDictionary_3 中 key=1 的值/資料內容(value)
print(myDictionary_3[1])
print(myDictionary_3[0:3])  # 錯誤,dictionary 沒有位置和順序,list的slice方法不能使用,會導致 TypeError

而且,因為 dictionary 是無序的(unordered),所以元素的順序對 dictionary 沒有意義,但對 list 就不一樣了。[1,2,3]和[2,1,3]是兩個不一樣的 list,而 {'name':'Jack','age':20} 和 {'age':20,'name':'Jack'} 對 Python 來說則是相同的,試試以下的例子:

# Python dictionary examples  @author: Sean Lu.
myList_1=[1,2,3]
myList_2=[2,1,3]
myDictionary_1={'name':'Jack','age':20}
myDictionary_2={'age':20,'name':'Jack'}
print(myList_1 == myList_2)  # list 順序不同是不同的
print(myDictionary_1 == myDictionary_2)  # 被視為相同的 dictionary

接下來看看 dictionary 資料型態常用的方法(methods),您會對 dictionary 和 list 的差異更清楚。

len(dic) - 回傳長度(元素/資料個數)
和 len() 使用在 list, tuple, string 資料型態一樣,會回傳 dictionary dic 裡的元素/資料個數。既然可以取得長度,那可不可以像 list 一樣,用 for loop 讀出整個 dictionary 呢?試試看以下的例子:

# Python dictionary examples  @author: Sean Lu.
# The len() method.
myDictionary_1={'name':'Jack','age':20}  # 設定一個 dictionary
print(len(myDictionary_1))  # 取得 dictionary 長度
myDictionary_1['gender']='male'  # 加入一組新的元素/資料 key-value pair
myDictionary_1['zodiac']='Pisces'  # 加入一組新的元素/資料 key-value pair
print(len(myDictionary_1))  # 取得 dictionary 長度
for i in range(len(myDictionary_1)):  # 以for loop讀出dictionary所有元素
    print(myDictionary_1[i])  # 錯誤,用位置當索引,會導致 KeyError
for i in myDictionary_1:  # 那這樣可不可以?
    print(i)

第一個 for loop 的問題和前述一樣,dictionary 不能用位置當索引,會導致 KeyError。第二個 for loop 是可執行的,但只會列出所有的 key。若您想取出 dictionary 裡完整的 key-value pair,得用後面介紹的方法。

dic.get(key[,default]) - 讀取元素
get() 方法就和前述讀取 dictionary 元素 myDictionary_1['name'] 一樣,讀出 dictionary 中某個 key 的 value 值,不一樣的地方是,若要讀取的 key 不存在於該 dictionary 中,myDictionary_1['name'] 這個方法會傳回 KeyError,但 get() 不會。get() 會回傳參數 default 所定的值,預設是 None,這是 get() 比 myDictionary_1['name'] 好用的地方。試試以下的例子:

# Python dictionary examples  @author: Sean Lu.
# The get() mothod.
myDictionary_1={'name':'Jack','age':20}  # 設定一個 dictionary
print(myDictionary_1['name'])  # 讀取 myDictionary_1 中 key='name' 的值/資料內容(value)
print(myDictionary_1['gender'])  # 錯誤,不存在的 key,會導致 KeyError
print(myDictionary_1.get('gender'))  # key='gender'不存在,回傳預設 None
print(myDictionary_1.get('gender','No data'))  # key='gender'不存在,回傳參數 'No data'
print(myDictionary_1)

in, not in 運算元(operator)
這兩個運算元用來判斷 key 是否存在 dictionary 中,前面介紹的 del dic[key] 可以刪除 dictionary 的元素/資料,但若該 key 並不存在,刪除它就會產生 KeyError,這時就可以用 in/ not in 先判斷一下 key 是否存在,如下例:

# Python dictionary examples  @author: Sean Lu.
myDictionary_1={'name':'Jack','age':20}  # 設定一個 dictionary
myDictionary_1['gender']='male'  # 加入一組新的元素/資料 key-value pair
myDictionary_1['zodiac']='Pisces'  # 加入一組新的元素/資料 key-value pair
print(myDictionary_1)
if 'birthday' in myDictionary_1:
    del myDictionary_1['birthday']
else:
    print('不存在 birthday 為 key 的資料!')
del myDictionary_1['birthday']  # 錯誤,刪除不存在的 key,會導致 KeyError
print(myDictionary_1)

dic.keys(), dic.values(), dic.items() - 回傳 dictionary 的鍵(key), 值(value), 鍵值對(key-value pair)
這3個方法就是我們用來取得 dictionary 內所有鍵(key), 值(value), 鍵值對(key-value pair)的方式,而且通常會和 for loop 結合在一起使用,它們會以 dictionary view 物件回傳 dictionary 的鍵(key), 值(value), 鍵值對(key-value pair)。dictionary view 物件看起來很像 list,但不是 list,同樣不能直接排序。看看以下的例子了解它們的用法:

# Python dictionary examples  @author: Sean Lu.
# The keys(), values(), items() mothod.
myDictionary_1={'name':'Jack','age':20}  # 設定一個 dictionary
myDictionary_1['gender']='male'  # 加入一組新的元素/資料 key-value pair
myDictionary_1['zodiac']='Pisces'  # 加入一組新的元素/資料 key-value pair
print(myDictionary_1.keys())
print(myDictionary_1.values())
print(myDictionary_1.items())

這3個方法回傳的 dictionary view 物件長這樣,很像 list 吧。注意 items() 回傳的 key-value pair 是 tuple 型態。
dict_keys(['name', 'age', 'gender', 'zodiac'])
dict_values(['Jack', 20, 'male', 'Pisces'])
dict_items([('name', 'Jack'), ('age', 20), ('gender', 'male'), ('zodiac', 'Pisces')])
假設有一個 dictionary 記錄了購買股票目前的投資報酬,您想找出那幾個股票的投資報酬是正的,可以這樣作:

# Python dictionary examples  @author: Sean Lu.
myDictionary_4={'台積電':0.203,'寶成':0.075,'味全':-0.013,'中信銀':-0.002,'義美':0.192,
'統一':-0.055,'鴻海':0.155}  # 股票投資報酬 dictionary
for v in myDictionary_4.values():
    if v>0:
        print(v)  # 列出投資報酬為正的值
for k,v in myDictionary_4.items():
    if v>0:
        print(k,v)  # 列出投資報酬為正的股票和其報酬

如果您想依投資報酬排序,但 dictionary 不能排序呀,那該怎麼辦?keys(), values(), items()回傳的 dictionary view 物件,雖然不能用 sort() 排序,卻可以用 sorted() 方法排序並回傳成 list,所以可以用 sorted() 對 dictionary 的 key, value 進行排序,方法如下:

# Python dictionary examples  @author: Sean Lu.
myDictionary_4={'台積電':0.203,'寶成':0.075,'味全':-0.013,'中信銀':-0.002,'義美':0.192,
'統一':-0.055,'鴻海':0.155}  # 股票投資報酬 dictionary
print(sorted(myDictionary_4.keys()))  # 對keys排序
print(sorted(myDictionary_4.values()))  # 對values排序
for k,v in sorted(myDictionary_4.items(),key=lambda x:x[1],reverse=True):  # 對values作降冪排序
    print(k,v)

dic.setdefault(key[, default]) - 有條件的新增 dictionary 元素
如果字典 dic 中已存在 key,就回傳其 value,不然新增 key,以 default 為值,並回傳 default,若沒有設定 defaule 參數,預設為 None。這個方法好像好曲折,但它很有用喔!如果我們想計算某個 list, tuple 或字串中所有元素的出現次數,使用 setdefault 就很方便,先看一下它的基本使用方式:

# Python dictionary examples  @author: Sean Lu.
# The setdefault() mothod.
myDictionary_1={'name':'Jack','age':20}  # 設定一個 dictionary
myDictionary_1['gender']='male'  # 這是一般的加入方式,加入新元素/資料 key-value pair
myDictionary_1['zodiac']='Pisces'  # 加入新的元素/資料 key-value pair
print(myDictionary_1.setdefault('zodiac','Leo'))  # 加入星座資料,已存在,回傳原值
print(myDictionary_1.setdefault('blood','O'))  # 加入血型資料,不存在,加入新值並回傳
print(myDictionary_1)

您可以發現 setdefault() 方法就是這段程式的精簡版(這段程式其實還可以更精簡,但這樣呈現較能清楚表達 setdefault() 的原意):

# Python dictionary examples  @author: Sean Lu.
# The setdefault() mothod.
myDictionary_1={'name':'Jack','age':20}  # 設定一個 dictionary
if 'gender' in myDictionary_1:
    print(myDictionary_1['gender'])  # 如果該key已存在,回傳其value
else:
    myDictionary_1['gender']='male'  # 如果該key不存在,新增並回傳value
    print(myDictionary_1['gender'])
print(myDictionary_1)

再來看看 setdefault() 方法可以怎麼應用,如果我們有一段句子,我們想統計這段句子裡每個字元出現的次數,可以這樣作:

# Python dictionary examples  @author: Sean Lu.
# The setdefault() mothod.
myContent='This is an example to count the characters in this sentence.'
countDic={}  # 設定一個字典存放字元出現次數
for c in myContent:
    countDic.setdefault(c,0)  # 如果該字元尚未存在,新增該字元,value為0
    countDic[c]+=1  # 將該字元的出現次數+1
print(countDic)

使用 setdefault() 我們可以很快速的統計元素出現的次數,並將結果存放在 dictionary 中。

dic.clear() - 清除整個 dictionary
將 dictionary 中所有的元素都刪除,使用如下:

# Python dictionary examples  @author: Sean Lu.
# The clear() mothod.
myDictionary_1={'name':'Jack','age':20}  # 設定一個 dictionary
myDictionary_1['gender']='male'  # 加入一組新的元素/資料 key-value pair
print(myDictionary_1)
myDictionary_1.clear()  # 清除整個 dictionary
print(myDictionary_1)

以上是 dictionary 常用的功能,若您想更仔細的了解 dictionary,可以到 Python3.6.3 官方文件(4.10. Mapping Types — dict) 章節,這裡有更完整的介紹。
接下來我們用一個例子來進一步了解 dictionary 的運用,假設我們的手機裡有這樣一份通訊錄,這份資料分別是姓名、性別、出生月份、血型和 LINE_ID,我們可以用什麼資料型態來處理它呢?

劉備, 男, 11, O, liupei
孫權, 男, 7, A, sunking
孫尚香, 女, 9, O, sunsister
曹操, 男, 10, B, ilikepretty
孔明, 男, 10, AB, ming
小喬, 女, 8, B, joverypretty
大喬, 女, 8, A, jothepretty
關羽, 男, 8, O, redface
張飛, 男, 9, A, feifei

在 list 那一篇介紹中是以 list 來處理,dictionary 是不是也可以?用這兩種不同的資料型態處理,會有什麼差異?我們來試試用 dictionary 處理它。因為 dictionary 是鍵值對(key-value pair),這份通訊錄可能設定成這樣:

myLineDic = {{'name': '劉備', 'gender': '男', 'birth': 11, 'blood': 'O', 'LIND_ID': 'liupei'},
             {'name': '孫權', 'gender': '男', 'birth': 7, 'blood': 'A', 'LIND_ID': 'sunking'},
             {'name': '孫尚香', 'gender': '女', 'birth': 9, 'blood': 'O', 'LIND_ID': 'sunsister'},
             {'name': '曹操', 'gender': '男', 'birth': 10, 'blood': 'B', 'LIND_ID': 'ilikepretty'},
             {'name': '孔明', 'gender': '男', 'birth': 10, 'blood': 'AB', 'LIND_ID': 'ming'},
             {'name': '小喬', 'gender': '女', 'birth': 8, 'blood': 'B', 'LIND_ID': 'joverypretty'},
             {'name': '大喬', 'gender': '女', 'birth': 8, 'blood': 'A', 'LIND_ID': 'jothepretty'},
             {'name': '關羽', 'gender': '男', 'birth': 8, 'blood': 'O', 'LIND_ID': 'redface'},
             {'name': '張飛', 'gender': '男', 'birth': 9, 'blood': 'A', 'LIND_ID': 'feifei'}}

這樣設定一個 dictionary myLineDic 可以嗎?
答案是不行喔,因為 dictionary 必須是鍵值對(key-value pair),雖然每筆資料裡都是鍵值對,但以人為單位那一整筆資料卻不是。我們可以把最外層設定成 list 來解決,把每一筆 dictionary 資料放在 list 裡,如下這樣是可以的。
方法1,最外層設定成 list,這是一個內容是 dictionary 的 list:

myLineList = [{'name': '劉備', 'gender': '男', 'birth': 11, 'blood': 'O', 'LIND_ID': 'liupei'},
              {'name': '孫權', 'gender': '男', 'birth': 7, 'blood': 'A', 'LIND_ID': 'sunking'},
              {'name': '孫尚香', 'gender': '女', 'birth': 9, 'blood': 'O', 'LIND_ID': 'sunsister'},
              {'name': '曹操', 'gender': '男', 'birth': 10, 'blood': 'B', 'LIND_ID': 'ilikepretty'},
              {'name': '孔明', 'gender': '男', 'birth': 10, 'blood': 'AB', 'LIND_ID': 'ming'},
              {'name': '小喬', 'gender': '女', 'birth': 8, 'blood': 'B', 'LIND_ID': 'joverypretty'},
              {'name': '大喬', 'gender': '女', 'birth': 8, 'blood': 'A', 'LIND_ID': 'jothepretty'},
              {'name': '關羽', 'gender': '男', 'birth': 8, 'blood': 'O', 'LIND_ID': 'redface'},
              {'name': '張飛', 'gender': '男', 'birth': 9, 'blood': 'A', 'LIND_ID': 'feifei'}]

但如果我們希望這是一個完全的 dictionary 要怎麼辦?一個方法是把 name 當成 key,像這樣 '劉備':{'gender': '男', 'birth': 10, 'blood': 'O', 'LIND_ID': 'liupei'},這樣每筆資料就是鍵值對(key-value pair)了,而人名都變成了 key。前面說過 dictionary 的 key 不能重複,所以如果有另一個朋友也叫'劉備',那就加不進這個通訊錄裡了。
方法2,把人名當 key:

myLineDic = {'劉備': {'gender': '男', 'birth': 11, 'blood': 'O', 'LIND_ID': 'liupei'},
             '孫權': {'gender': '男', 'birth': 7, 'blood': 'A', 'LIND_ID': 'sunking'},
             '孫尚香': {'gender': '女', 'birth': 9, 'blood': 'O', 'LIND_ID': 'sunsister'},
             '曹操': {'gender': '男', 'birth': 10, 'blood': 'B', 'LIND_ID': 'ilikepretty'},
             '孔明': {'gender': '男', 'birth': 10, 'blood': 'AB', 'LIND_ID': 'ming'},
             '小喬': {'gender': '女', 'birth': 8, 'blood': 'B', 'LIND_ID': 'joverypretty'},
             '大喬': {'gender': '女', 'birth': 8, 'blood': 'A', 'LIND_ID': 'jothepretty'},
             '關羽': {'gender': '男', 'birth': 8, 'blood': 'O', 'LIND_ID': 'redface'},
             '張飛': {'gender': '男', 'birth': 9, 'blood': 'A', 'LIND_ID': 'feifei'}}

我們也可以增加一個 ID 當作 key,像這樣 P0001:{'name': '劉備', 'gender': '男', 'birth': 10, 'blood': 'O', 'LIND_ID': 'liupei'},這樣也可以,要怎麼作比較好,沒有一定的答案,看您的資料使用需求。
方法3,增加一個不重複的 ID 當 key:

myLineDic = {'P0001':{'name': '劉備', 'gender': '男', 'birth': 11, 'blood': 'O', 'LIND_ID': 'liupei'},
             'P0002':{'name': '孫權', 'gender': '男', 'birth': 7, 'blood': 'A', 'LIND_ID': 'sunking'},
             'P0003':{'name': '孫尚香', 'gender': '女', 'birth': 9, 'blood': 'O', 'LIND_ID': 'sunsister'},
             'P0004':{'name': '曹操', 'gender': '男', 'birth': 10, 'blood': 'B', 'LIND_ID': 'ilikepretty'},
             'P0005':{'name': '孔明', 'gender': '男', 'birth': 10, 'blood': 'AB', 'LIND_ID': 'ming'},
             'P0006':{'name': '小喬', 'gender': '女', 'birth': 8, 'blood': 'B', 'LIND_ID': 'joverypretty'},
             'P0007':{'name': '大喬', 'gender': '女', 'birth': 8, 'blood': 'A', 'LIND_ID': 'jothepretty'},
             'P0008':{'name': '關羽', 'gender': '男', 'birth': 8, 'blood': 'O', 'LIND_ID': 'redface'},
             'P0009':{'name': '張飛', 'gender': '男', 'birth': 9, 'blood': 'A', 'LIND_ID': 'feifei'}}

我們用方法2把人名當 key,請試試看使用這個通訊錄,加入新朋友(貂嬋,女,8,O,iampretty),分別找出男生以及生日在8月的女生,並將所有人依照生日月份由小到大排序。您可以進一步比較看看,這個通訊錄用 dictionary 結構和使用 list 結構,有什麼差別?優缺點各是什麼?

# Python dictionary examples  @author: Sean Lu.
# An application of dictionary, search and sorting.
import pprint
myLineDic = {'劉備': {'gender': '男', 'birth': 11, 'blood': 'O', 'LIND_ID': 'liupei'},
             '孫權': {'gender': '男', 'birth': 7, 'blood': 'A', 'LIND_ID': 'sunking'},
             '孫尚香': {'gender': '女', 'birth': 9, 'blood': 'O', 'LIND_ID': 'sunsister'},
             '曹操': {'gender': '男', 'birth': 10, 'blood': 'B', 'LIND_ID': 'ilikepretty'},
             '孔明': {'gender': '男', 'birth': 10, 'blood': 'AB', 'LIND_ID': 'ming'},
             '小喬': {'gender': '女', 'birth': 8, 'blood': 'B', 'LIND_ID': 'joverypretty'},
             '大喬': {'gender': '女', 'birth': 8, 'blood': 'A', 'LIND_ID': 'jothepretty'},
             '關羽': {'gender': '男', 'birth': 8, 'blood': 'O', 'LIND_ID': 'redface'},
             '張飛': {'gender': '男', 'birth': 9, 'blood': 'A', 'LIND_ID': 'feifei'}}
# 加入一位新朋友 貂嬋,女,8,O,iampretty,以下兩個方法都可以使用
myLineDic['貂嬋']={'gender': '女', 'birth': 8, 'blood': 'O', 'LIND_ID': 'iampretty'}
myLineDic.setdefault('貂嬋',{'gender': '女', 'birth': 8, 'blood': 'O', 'LIND_ID': 'iampretty'})
pprint.pprint(myLineDic)
# 列出所有男生
for k,v in myLineDic.items():
    if v['gender']=='男':
        print(k)
# 列出所有生日在8月的女生
for k,v in myLineDic.items():
    if v['gender']=='女' and v['birth']==8:
        print(k)
# 所有人依照生日月份由小到大排序
for k,v in sorted(myLineDic.items(),key=lambda x:x[1]['birth']):
    print(k)

這樣您是否已經了解 dictionary 資料型態的使用方式?測驗一下自己,試試看以下這個例子:
這是虛構的三國時代各國武將戰鬥經驗列表,請將這個列表用 dictionary 資料結構呈現,並進行下列動作:
武將名(name), 國家(country), 等級(level), 勝(winning), 負(failure), 戰鬥經驗(exp)
呂布,None,20,12,3,22000
關羽,蜀,15,21,9,26890
趙雲,蜀,19,18,0,28287
張飛,蜀,12,15,8,13212
馬超,蜀,5,20,13,29694
典韋,魏,18,21,17,27187
許楮,魏,18,17,20,12466
張遼,魏,8,18,10,17881
甘寧,吳,13,11,5,16906
黃忠,蜀,8,29,16,11054
孫策,吳,10,29,17,28437
魏延,蜀,19,23,23,22762
王平,蜀,7,19,6,23831
祖茂,吳,9,22,19,14087
凌統,吳,16,18,5,27422
太史慈,吳,14,29,14,26618
呂蒙,吳,6,18,15,28803
黃蓋,吳,13,22,13,21950
夏侯敦,魏,10,12,10,23325
夏侯淵,魏,11,13,8,26713
夏侯惇,魏,17,19,11,15382
徐晃,魏,16,22,19,29846
龐德,魏,6,21,7,22740
甘寧,吳,16,15,9,15044
周泰,吳,18,17,10,14306
張郃,蜀,12,11,8,29264

(1)幫蜀國加入一名武將:姜維,蜀,等級7,勝12,負2,戰鬥經驗18300。
(2)計算出各國各有幾名武將?並依數量由大到小以蜀國:3名,魏:2名,吳:2名方式顯示。
(3)蜀國欲對魏國發動攻擊,請以戰鬥經驗依序(由高到低)列出蜀國前3名大將。
(4)各國欲對武將論功行賞,獎金計算方式為((等級+勝-負)*戰鬥經驗),請計算出各武將的年終獎金,並新增獎金(bonus)欄位加入 dictionary 中。
(註)以上資料筆數很多,可別一筆一筆辛苦的改成 dictionary 喔,網路上有工具可以快速轉換格式,試試用 CSV to JSON 幫您把 dictionary 格式處理好。

參考資料 (References):
😺 Python3.6.3 官方文件(5.5. Dictionaries)
😺 Python3.6.3 官方文件(4.10. Mapping Types — dict)
😺 Automatethe Boring Stuff with Python: Practical Programming for Total Beginners, by AlSweigart, No Starch Press; 1 edition (April 14, 2015)