05 - 字典

  • 字典
  • 字典的迭代
  • 常用的資料型別
  • 補充知識-字典相關好用功能

字典

  • 字典用大括號{}宣告,每個 key 及其對應的 value 為一組元素
    {key1:value1, key2:value2}
  • key 需為不可變物件 (eg. intfloatstr),且需唯一
  • d[key]:字典以鍵值 key 去取資料 value,很像是串列的索引 index
  • d[key] = 物件 :字典以鍵值 key 去指向資料,
    如果 key 不存在會自動建立,否則會指向新值。
In [1]:
l = [20,25,10]
print(l[0])
20
In [2]:
d = {"Mars":20,"姿君":25,"毛毛":10}
print(d["Mars"])
d["毛毛"] =15
d["noname"] = 30
print(d)
20
{'Mars': 20, '姿君': 25, '毛毛': 15, 'noname': 30}

想像 會員儲值 的情境

  • Mars剛開始有 $20、姿君有 $25、毛毛有 $10
  • Mars儲值 $15、姿君儲值 $5
In [3]:
l = [["Mars",20],["姿君",25],["毛毛",10]]
# Mars 儲值 15元, 再來是 姿君儲值 5元
l[0][1]+=15
l[1][1]+=5
print(l)
[['Mars', 35], ['姿君', 30], ['毛毛', 10]]
In [4]:
# 比較有彈性
l = [["Mars",20],["姿君",25],["毛毛",10]]
for member in l:
    if member[0]=="Mars":
        member[1]+=15
for member in l:
    if member[0]=="姿君":
        member[1]+=5
print(l)
[['Mars', 35], ['姿君', 30], ['毛毛', 10]]
In [5]:
d = {"Mars":20,"姿君":25,"毛毛":10}
d["Mars"] += 15
d["姿君"] += 5
print(d)
print(d["Mars"],d["姿君"])
{'Mars': 35, '姿君': 30, '毛毛': 10}
35 30

注意!

  • 字典是可變物件
  • 取用不存在的 key,會出錯
In [6]:
d = {} # 空字典
print(id(d))
d["Mars"] = 20
d["姿君"] = 25
d["毛毛"] = 10
print(d)
print(len(d))
print(id(d))
4528636912
{'Mars': 20, '姿君': 25, '毛毛': 10}
3
4528636912
In [7]:
print(d['MarsW'])
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-7-8ab309ac3ada> in <module>()
----> 1 print(d['MarsW'])

KeyError: 'MarsW'

[練習] 計算庫存

水果庫存、價格都以字典型別儲存,
請計算若水果都賣出後,可賺進多少錢?

stock={
    "banana":5,
    "apple":3,
    "orange":10
}
price={
    "banana":5,
    "apple":20,
    "orange":15
}

Hint:

revenue = 0
revenue += stock["____"] * price["____"]
revenue += stock["____"] * price["____"]
revenue += stock["____"] * price["____"]
print(revenue)

字典的迭代

在 Python 中,迭代、迴圈的使用率很高,
小技巧就是每個東西都用迴圈跑一下,印出裡面的元素,
會很快的了解資料結構的內容!

In [8]:
s = "loop"
for char in s:
    print(char)
l
o
o
p
In [9]:
print(s[0])
print(s[1])
print(s[2])
print(s[3])
l
o
o
p
In [10]:
l = [1,2,3]
for ele in l:
    print(ele)
1
2
3
In [11]:
print(l[0])
print(l[1])
print(l[2])
1
2
3
In [12]:
# 字典以鍵值 key 去存取資料 value
d = {"Mars":20,"姿君":25,"毛毛":10}
for key in d:
    print(key)
Mars
姿君
毛毛
In [13]:
d = {"Mars":20,"姿君":25,"毛毛":10}
for key in d:
    print(key,d[key])
Mars 20
姿君 25
毛毛 10
In [14]:
print("Mars",d["Mars"])
print("姿君",d["姿君"])
print("毛毛",d["毛毛"])
Mars 20
姿君 25
毛毛 10

[練習] 計算庫存-以迴圈處理

水果庫存、價格都以字典型別儲存,
請計算若水果都賣出後,可賺進多少錢?

stock={
    "banana":5,
    "apple":3,
    "orange":10
}
price={
    "banana":5,
    "apple":20,
    "orange":15
}

Hint:

revenue = 0
for fruit in stock:
    revenue += stock[____] * price[____]
print(revenue)

[進階練習] 計算庫存-以迴圈處理、另一種儲存方式

改了儲存方式,請計算若水果都賣出後,可賺進多少錢?

product = {
    "banana":{
        "stock":5,
        "price":5
    },
    "apple":{
        "stock":3,
        "price":20
    },
    "orange":{
        "stock":10,
        "price":15
    }
}

Hint:

先把資料直接丟入迴圈,看會印出什麼元素~
確定拿到的元素是對的,再進行處理!
(試試印出香蕉的庫存)

常用的資料型別

In [15]:
# 拿出每個元素,再拿出該元素的子元素(名字,分數)
l = [["姿君",25],["Mars",20],["毛毛",10]]
for item in l:
    name = item[0]
    score = item[1]
    print(name,score)
姿君 25
Mars 20
毛毛 10
In [16]:
# 比較簡短的寫法
l = [["Mars",20],["姿君",25],["毛毛",10]]
for name,score in l:
    print(name,score)
Mars 20
姿君 25
毛毛 10
In [17]:
# 拿到名字,分數,就可以用 名字當 key、分數當 value
l = [["Mars",20],["姿君",25],["毛毛",10]]
d = {}
for name,score in l:
    print(name,score)
    d[name]=score
print(d)
Mars 20
姿君 25
毛毛 10
{'Mars': 20, '姿君': 25, '毛毛': 10}

[練習]

前面的範例有個會員儲值的情境:

d = {"Mars":20,"姿君":25,"毛毛":10}
d["Mars"] += 15 # !
d["姿君"] += 5   # !
print(d)

把儲值改成串列內容,試著用迴圈取串列中的值,做到一樣的事情:
Mars 儲值 15 => 35
姿君 儲值 5 => 30

d = {"Mars":20,"姿君":25,"毛毛":10}
l = [["Mars",15],["姿君",5]]
for name,money in ____:
    _[___]+=____
print(d)

[進階練習] 遊戲計分

遊戲中計分,第一回合:A 得 10 分、第二回合 B 得 5 分...,最後要加總算分數。

l = [["A",10],["B",5],["C",23],["B",7],["A",6],["A",3],["C",2]]

答案是:

C的得分25
B的得分12
A的得分19

Hint:

可以參考剛才提到的「如何把串列變成字典」:

  • 先拿出各元素
  • 再拿出各元素的子元素:名字、分數
l = [["A",10],["B",5],["C",23],["B",7],["A",6],["A",3],["C",2]]
for _____ in l:
    print(___,___)

會得到以下結果

A 10
B 5
C 23
.
.
.

然後因為要計算總分,
所以每次拿到新的分數 value
是要「加回原本對應 名字(key) 的分數(value)」
eg.

第一回合,A 得 10 分 => A 目前總分為 10 分  
第二回合,B 得  5 分 => B 目前總分為  5 分 *
第三回合,C 得 23 分 => C 目前總分為 23 分
第四回合,B 得  7 分 => B 目前總分為 12 分 * (原來的 5 分加上這次的 7 分)
.
.
l = [["A",10],["B",5],["C",23],["B",7],["A",6],["A",3],["C",2]]
d = {"A":0, "B":0, "C":0}

for _____ in l:
    print(___,___)
    d[___] = ______

for key in d:
    print("{}的得分{}".format(key,d[key]))

如果不知道有幾個玩家

In [18]:
l = [["A",10],["B",5],["C",23],["B",7],["A",6],["A",3],["C",2]]
d = {}
for name,score in l:
    if name not in d: # 檢查是否存在這個玩家
        d[name]=0     # 不存在就把他的得分設為預設值0
    d[name]+=score
for key in d:
    print("{}的得分{}".format(key,d[key]))
A的得分19
B的得分12
C的得分25

純文字形式的遊戲計分

  • 可以轉成前面練習題的串列型別
In [19]:
score_log = """
A,10
B,5
C,23
B,7
A,6
A,3
C,2
"""
l = []
for line in score_log.split("\n"):
    print(line.split(","))
    if len(line.split(","))==2:
#     if "," in line:
        name,score = line.split(",")
        l.append([name,int(score)])
print(l)
['']
['A', '10']
['B', '5']
['C', '23']
['B', '7']
['A', '6']
['A', '3']
['C', '2']
['']
[['A', 10], ['B', 5], ['C', 23], ['B', 7], ['A', 6], ['A', 3], ['C', 2]]

應用情境:正規化

  • 星期、月份
  • 中文數字 (eg. 三、參、叄)
In [20]:
datetime = "Oct 18"
month,date = datetime.split(" ")
month = month.replace("Oct","10")
format_date = "{}/{}".format(month,date)
print (format_date)
10/18
In [21]:
datetime = "Oct 18"
month,date = datetime.split(" ")
month_dict = {
    #......
    "10":["Oct","October"],
    "11":["Nov","November"],
    "12":["Dec","December"],
}
for key in month_dict:
    print(key,month_dict[key])
    for keyword in month_dict[key]:
        if month==keyword:
            month = month.replace(month,key)
format_date = "{}/{}".format(month,date)
print (format_date)
10 ['Oct', 'October']
11 ['Nov', 'November']
12 ['Dec', 'December']
10/18

補充知識-字典相關好用功能

  • 取不存在的 key 值
  • 有預設值的字典

取值

  • 字典[key]:key 不存在會報錯
  • 字典.get(key,default):key 不存在會回傳default
    • default 預設為None
In [22]:
d = {"A":1, "B":2, "C":3}
print(d["A"])
print(d.get("A"))
1
1
In [23]:
d = {"A":1, "B":2, "C":3}
print(d.get("D"))
print(d.get("D",0))
print(d["D"])
None
0
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-23-628ad431d9da> in <module>()
      2 print(d.get("D"))
      3 print(d.get("D",0))
----> 4 print(d["D"])

KeyError: 'D'

應用情境:判斷式過於冗長

In [24]:
ticket_type="敬老票" 
if ticket_type=="學生票":
    price=270
elif ticket_type=="敬老票":
    price=250
else:
    price=300
print("{}價格為{}".format(ticket_type,price))
敬老票價格為250
In [25]:
ticket_type="敬老票" 
d = {"學生票":270,"敬老票":250}
price = d.get(ticket_type,300)
print("{}價格為{}".format(ticket_type,price))
敬老票價格為250

有預設值的字典

from collections import defaultdict
d = defaultdict(物件型別)
  • 物件型別若不指定,預設為 None
  • 並不是原生的字典型別,但有跟原生字典型別同樣的操作方式
  • 就算 key 不存在,直接用 字典[key] 也沒關係=>會生成預設值
In [26]:
from collections import defaultdict

print("int()的預設值為",int())
d = defaultdict(int) 
print(d)

print(d["a"])
print(dict(d))
int()的預設值為 0
defaultdict(<class 'int'>, {})
0
{'a': 0}

可以改寫前面的遊戲計分練習題

In [27]:
l = [["A",10],["B",5],["C",23],["B",7],["A",6],["A",3],["C",2]]
d = {}
for name,score in l:
    if name not in d: # 檢查是否存在這個玩家
        d[name]=0     # 不存在就把他的得分設為預設值0
    d[name]+=score
for key in d:
    print("{}的得分{}".format(key,d[key]))
A的得分19
B的得分12
C的得分25
In [28]:
from collections import defaultdict
d = defaultdict(int) 

for name,score in l:    
    d[name]+=score
for key in d:
    print("{}的得分{}".format(key,d[key]))
A的得分19
B的得分12
C的得分25
In [29]:
from collections import defaultdict

print("list()的預設值為",list())
d = defaultdict(list) 

print(d["a"])  
print(dict(d))
list()的預設值為 []
[]
{'a': []}

應用情境-歸類同分學生

In [30]:
from collections import defaultdict
l = [["David",70],["Mars",58],["Kelly",90],["Bob",40],["Amy",58]]
d = defaultdict(list) 
for name,score in l:
    d[score].append(name)

for key in d:
    print("{}分 的學生有 {}".format(key,",".join(d[key])))
70分 的學生有 David
58分 的學生有 Mars,Amy
90分 的學生有 Kelly
40分 的學生有 Bob