# 字典 (dictionary)
- 跟串列類似,都是一種儲存資料的容器
- 字典內的元素是以鍵值對(key-value pairs)的形式存在,key是不能重複的。
- 字典的 key 需要是 [immutable(不可更改)](https://medium.com/starbugs/python-mutable-%E8%88%87-immutable-8ef7804181cd)且 hashable(唯一雜湊值 → 唯一)。

- 字典 (dictionary)是基於[哈希表(Hash Table)](https://alrightchiu.github.io/SecondRound/hash-tableintrojian-jie.html)的資料結構。
## 串列與字典的差異
| | list | dictionary |
| -------- | -------- | -------- |
| 表示方法 | list1 = [ 10, 20, 30 ] | dict1 = { "apple":10, "banana":20, "orange":30 } |
| index | index從0開始分配,每個element都會到分配一個index。(順序性 sequential) | 以key-value為一組,使用key來查找value。 |
| 插入及查找速度 | 插入及查找速度較慢 | 較快,"理論上"不會應為key增加而變慢 |
| 占用的記憶體空間 | 較小 | 較大的記憶體空間 (空間換取時間)
## 建立一個空字典
```python=
#方法一
dict = {}
print(dict) # 輸出:{}
#方法二
dict = dict()
print(dict) # 輸出:{}
```
## 初始化一個字典
```python=
#dict = {key1:value1, key2:value2, ...}
dict = {
"name" : "Bob",
"age" : 18,
"ID" : "E12345678"
}
print(dict) # 輸出:{'name': 'Bob', 'age': 18, 'ID': 'E12345678'}
```
字典的key必須是唯一的,所以key必須是不可變的物件(Immutable Objects)
所以像是list、dictionary、set這類物件都不能當作key。
而value則沒有此限制
```python=
dict = {
"name" : ["Bob", "Jim", "Jack"],
"age" : [18, 20, 21],
"ID" : ["E12345678", "D12345678", "C12345678"]
}
print(dict) # 輸出:{'name': ['Bob', 'Jim', 'Jack'], 'age': [18, 20, 21], 'ID': ['E12345678', 'D12345678', 'C12345678']}
```
value甚至可以是字典,
```python=
dict = {
"student1" : {"name" : "Bob", "age" : 18, "ID" : "E12345678"},
"student2" : {"name" : "Jim", "age" : 20, "ID" : "D12345678"},
}
print(dict) # 輸出:{'student1': {'name': 'Bob', 'age': 18, 'ID': 'E12345678'}, 'student2': {'name': 'Jim', 'age': 20, 'ID': 'D12345678'}}
```
## 字典的基本操作
- ### 查找
```python=
dict = {
"name" : ["Bob", "Jim", "Jack"],
"age" : [18, 20, 21],
"ID" : ["E12345678", "D12345678", "C12345678"]
}
print(dict[name]) # 輸出:['Bob', 'Jim', 'Jack']
```
- ### 新增元素
```python=
dict = {
"name" : "Bob",
"age" : 18,
"ID" : "E12345678"
}
dict["score"] = 90
print(dict) # 輸出:{'name': 'Bob', 'age': 18, 'ID': 'E12345678', 'score': 90}
```
- ### 修改元素
```python=
dict = {
"name" : "Bob",
"age" : 18,
"ID" : "E12345678"
}
dict["name"] = "Jack"
print(dict) # 輸出:{'name': 'Jack', 'age': 18, 'ID': 'E12345678'}
```
- ### 刪除元素
```python=
dict = {
"name" : "Bob",
"age" : 18,
"ID" : "E12345678"
}
#dict[key] = value
dict.pop("ID")
print(dict) # 輸出:{'name': 'Bob', 'age': 18}
```
## 字典的進階操作
1. `get()`方法
查到不存在的鍵值對時,返回None,而不是報錯。
```python=
dict = {
"name" : "Bob",
"age" : 18,
"ID" : "E12345678"
}
print(dict.get("score")) # 輸出:None
```
1. `setdefault()`方法
查到不存在的鍵值對時,返回None,而不是報錯。
```python=
dict = {
"name" : "Bob",
"age" : 18,
"ID" : "E12345678"
}
print(dict.setdefault("score", 90)) #輸出:90
print(dict) #輸出:{'name': 'Bob', 'age': 18, 'ID': 'E12345678', 'score': 90}
```
1. `keys()`方法
返回所有key的動態視圖
```python=
dict = {
"name" : "Bob",
"age" : 18,
"ID" : "E12345678"
}
print(dict.keys()) # 輸出:dict_keys(['name', 'age', 'ID'])
```
2. `values()方法`
返回所有的value動態視圖
```python=
dict = {
"name" : "Bob",
"age" : 18,
"ID" : "E12345678"
}
print(dict.values()) # 輸出:dict_values(['Bob', 18, 'E12345678'])
```
3. `update()方法`
批量新增、修改元素
```python=
dict = {
"name" : "Bob",
"age" : 18,
"ID" : "E12345678"
}
dict.update({"score" : 90, "major" : "ES", "age" : 20})
print(dict) # 輸出:{'name': 'Bob', 'age': 20, 'ID': 'E12345678', 'score': 90, 'major': 'ES'}
```
5. `clear()方法`
清空字典
```python=
dict = {
"name" : "Bob",
"age" : 18,
"ID" : "E12345678"
}
dict.clear()
print(dict) # 輸出:{}
```
## 更多的字典方法
dict1 = {"Bob":50, "Anna":80, "Jack":90}
| 方法 | 意義 | 範例 |結果 |
| -------- | -------- | -------- | -------- |
|len(dict1) | 取得字典元素個數 | n=len(dict1)| n=3 |
|dict1.copy()| 複製字典 | dict2= dict1.copy() | dict2 = {"Bob":50, "Anna":80, "Jack":90} |
|鍵 in dict1 | 檢查鍵是否存在 | b="Bob" in dict1| b=True |
# 集合(set)
- 一個集合裡所有的鍵都不會重複,元素裡的內容可以是整數(int)、浮點數(float)、字串(string)、元組(tuple)、布林(boolen),但是不可以是串列(list)、字典(dict)、集合(set)。
- 因為集合不會包含重複的資料的特性,常用來進行去除重複的字元、或判斷元素間是否有交集、聯集或差集之類的關聯性。
## 創建空集合
```python
fruits = set()
print(fruits) # 輸出:{}
```
## 創建集合
```python
fruits = set(["apple", "apple", "banana", "banana", "cherry"])
print(fruits) # 輸出:{'apple', 'banana', 'cherry'}
```
或
```python
fruits = {"apple", "apple", "banana", "banana", "cherry"}
print(fruits) # 輸出:{'apple', 'banana', 'cherry'}
```
## 集合的基本操作
- 新增元素
```python
fruits = {"apple", "banana", "cherry"}
fruits.add("orange")
print(fruits) # 輸出:{'apple', 'orange', 'banana', 'cherry'}
```
- 刪除元素
```python
fruits = {"apple", "banana", "cherry"}
fruits.remove("apple")
print(fruits) # 輸出:{'banana', 'cherry'}
```
## 集合的其他操作
1. clear()方法
清除集合
```python
fruits = {"apple", "banana", "cherry"}
fruits.clear()
print(fruits) # 輸出:set()
```
2. copy()方法:
複製集合中的元素成為一個新的集合,可以避免破壞原始的集合
```python
fruit = {"apple", "banana", "cherry"}
fruit_copy = fruit.copy()
fruit_copy.add("orange")
print(fruit) #輸出: {'cherry', 'apple', 'banana'}
print(fruit_copy) #輸出: {'orange', 'cherry', 'apple', 'banana'}
```
4. discard()方法:
刪除集合中指定的元素。若該指定的元素不存在也不會回傳KeyError。
```python=
fruit = {"apple", "banana", "cherry"}
fruit.discard("orange")
print(fruit) #輸出: {'banana', 'apple', 'cherry'}
fruit.remove("orange") #輸出: KeyError
```
5. update()方法:
A.update(B),將集合B的元素加入集合A中。
```python=
A = {"apple", "banana", "cherry"}
B = {"orange", "tomato"}
A.update(B)
print(A) #輸出: {'orange', 'tomato', 'cherry', 'apple', 'banana'}
```
## 集合運算

- 交集
```python
set1 = {"apple", "banana", "cherry"}
set2 = {"banana", "cherry", "orange"}
intersection = set1 & set2
print(intersection) # 輸出:{'banana', 'cherry'}
```
- 聯集
```python
set1 = {"apple", "banana", "cherry"}
set2 = {"banana", "cherry", "orange"}
union = set1 | set2
print(union) # 輸出:{'apple', 'banana', 'cherry', 'orange'}
```
- 差集
```python
set1 = {"apple", "banana", "cherry"}
set2 = {"banana", "cherry", "orange"}
difference = set1 - set2
print(difference) # 輸出:{'apple'}
```
- 對稱差集
```python
set1 = {"apple", "banana", "cherry"}
set2 = {"banana", "cherry", "orange"}
symmetric_difference = set1 ^ set2
print(symmetric_difference) # 輸出:{'apple', 'orange'}
```
- 子集
```python
set1 = {"apple", "banana"}
set2 = {"apple", "banana", "cherry"}
print(set1.issubset(set2)) # 輸出:True
print(set2.issubset(set1)) # 輸出:False
```
- 超集
```python
set1 = {"apple", "banana"}
set2 = {"apple", "banana", "cherry"}
print(set1.issuperset(set2)) # 輸出:False
print(set2.issuperset(set1)) # 輸出:Ture
```
> 參考:
> [5. 資料結構— Python 3.11.10 說明文件](https://docs.python.org/zh-tw/3.11/tutorial/datastructures.html#sets)
> [[Python教學] Dictionary 字典 和 Set 集合[Python教學]](https://utrustcorp.com/python_dictionary_set/)
> <a href='https://blog.csdn.net/weixin_47906106/article/details/121772942'>详解Python字典的底层原理——哈希表(Python面试必备)</a>
> <a href='https://www.cnblogs.com/jiakecong/p/15881370.html'>python字典底层原理</a>
> <a href='https://blog.csdn.net/be5yond/article/details/120021250'>Python 深入理解dict---为什么 dict 查询元素比 list 快?</a>
## Lab05作業題目
- 繳交方式 :請到[https://140.116.179.59:8080](https://140.116.179.59:8080)完成作業題目,並將程式碼加上註解(你的理解),很重要,否則助教有權利扣你分數
- 禁止抄襲,否則助教會來查水表
- 題目為基本題3題+1題加分題,共4題
- Lab05_01( 30分 )、Lab05_02( 40分 )、Lab05_03( 30分 )==(不符規定九折,未註解七折,遲交六折)==
- 加分題直接列入期末成績計算
- github檔名格式:
- 每一個檔案為:Lab05_OO.py
- 所有檔案放入資料夾學號_Lab05在將資料夾上傳