狠狠撸

狠狠撸Share a Scribd company logo
笔测迟丑辞苍元组,字典,集合
Revised on August 26, 2021
? Python的資料結構
? 元組資料與應用
? 字典資料與應用
? 集合資料與應用
? 使用sorted()函式
? 使用enumerate()函式
? 應用實例 – 井字棋遊戲
? Python 支援四種資料結構:list、tuple、set及dictionary,而且彼此
問可以相互轉換
? 串列類似其它程式語言的陣列 (Array),但Python 串列中的元素允許
是不同資料型別
list1 = ['apple', 23, 'orange', 15, 'melon', 19]
? 元組 (tuple) 類似串列,但建立資料後,內容就不可變更
tuple1 = ('apple', 23, 'orange', 15, 'melon', 19)
? 集合 (set) 為不重複的非排序元素集,可進行數學上的集合運算
set1 = {'apple', 23, 'orange', 15, 'melon', 19}
? 字典 (dictionary) 用於儲存由 key 索引的鍵?值配對 (Key-Value Pair)
資料,鍵必須是唯?
dict1 = {'apple':23, 'orange':15, 'melon':19}
Python的資料結構
2
? 元組 (tuple) 類似串列,元組的元素可以由不同型別的資料型別來組成,
但元組建立後元素個數及內容都不可變更
? 讀取元組內的元素時,使用的註標即建立時的順序,運算速度最快
? 元組的宣告
? 元組變數 = 元素A, 元素B, 元素C, ...
? 元組變數 = (元素A, 元素B, 元素C, ...)
tuple1 = () #宣告空元組
dummy1 = 65 #整數資料
tuple2 = 65, #宣告只有?個元素的元組,元素之後必須加上逗號
dummy2 = (65) #整數資料
tuple3 = (65,) #宣告只有?個元素的元組,元素之後必須加上逗號
tuple4 = (65, 'A') #元素可以是不同資料型別
print(tuple4[1]) #A
元組資料 1/2
? list 函式可將元組資料轉換為串列
mytuple = (1, 2, 3, 4, 5)
list1 = list(mytuple)
? tuple 函式可將串列資料轉換為元組
mylist = [1, 2, 3, 4, 5]
tuple1 = tuple(mylist)
元組資料 2/2
4
tuple1 = ('apple', 23, 'orange', 15, 'melon', 19)
tuple2 = (7, 20, 15, 40, 19.5)
? value in 元組
檢查元組中是否存在value元素值
print(50 in tuple1) #False
? 元組[i]
回傳註標為i的元素值
print(tuple2[0]) #apple
? len(元組)
取得元組元素數目
print(len(tuple1)) #6
? min(元組)
取得元組中最小的元素值,只適用於元素皆為數值資料之元組
print(min(tuple2)) #7
元組的基本操作 1/2
? max(元組)
取得元組中最大的元素值,只適用於元素皆為數值資料之元組
print(max(tuple2)) #40
? sum(元組)
計算元組元素的總和,只適用於元素皆為數值資料之元組
print(sum(tuple2)) #101.5
tuple1 = ('apple', 23, 'orange', 15, 'melon', 19)
tuple1[1] = 25 #錯誤
元組的基本操作 2/2
TypeError: 'tuple' object does not support item assignment
? 字典資料 (dict) 的元素由「鍵(Key):值(Value)」組成,元素間用逗號
分隔,所有元素被 {} 大括號包圍
? 字典 = {鍵1:值1, 鍵2:值2, ...}
? 鍵必須是唯?,如果鍵值重覆,前?鍵值的元素會被後?鍵值的元素覆
蓋。鍵可以使用數值、字串或元組
? 值可以是任何資料型別
dict1 = {'香蕉':20, '蘋果':50, '橘子':30}
dict2 = dict(?瓜 = 30, 葡萄 = 45, 百香果 = 60)
print(dict1)
print(dict2)
測試結果:
{'香蕉': 20, '蘋果': 50, '橘子': 30}
{'?瓜': 30, '葡萄': 45, '百香果': 60}
字典資料
7
dict1 = {'香蕉':20, '蘋果':50, '橘子':30}
? 字典[key] = value
在字典新增key:value元素,若已存在鍵,表示更新值
dict1['鳯梨'] = 40
? del 字典[key]
刪除字典中鍵為 key 的元素
del dict1['鳯梨']
? 字典.clear()
可刪除字典的所有元素
dict1.clear()
? del 字典
刪除整個字典資料
del dict1
字典資料維護 1/2
8
dict1 = {'香蕉':20, '蘋果':50, '橘子':30}
dict1['鳯梨'] = 40
print(dict1) #{'香蕉':20, '蘋果':50, '橘子':30, '鳯梨':40}
del dict1['蘋果']
print(dict1) #{'香蕉':20, '橘子':30, '鳯梨':40}
dict1.clear()
print(dict1) #{}
del dict1
print(dict1) #錯誤
字典資料維護 2/2
NameError: name 'dict1' is not defined
dict1 = {'香蕉':20, '蘋果':50, '橘子':30}
? len(字典)
計算字典的元素個數
print(len(dict1)) #3
? 字典.fromkeys(元組或串列[, 預設值])
以元組或串列元素為鍵,建立字典,如有重複元素會自動去除
fruits = ('apple', 'orange', 'melon')
fruitdic = {}.fromkeys(fruits, 30)
print(fruitdic) #{'apple': 30, 'orange': 30, 'melon': 30}
? 字典.keys()
傳回字典中所有的鍵,傳回資料可用 list 函式轉換為串列
print(list(dict1.keys())) #['香蕉', '蘋果', '橘子']
? 字典.values()
傳回字典中所有的值,傳回資料可用 list 函式轉換為串列
print(list(sites. values())) #[20, 50, 30]
字典資料處理 1/5
10
dict1 = {'香蕉':20, '蘋果':50, '橘子':30}
? 字典.items()
傳回字典中所有的元素,每?對鍵值會形成?個元組。傳回資料可用 list 函式
轉換為串列
print(list(dict1.items())) #[('香蕉', 20), ('蘋果', 50), ('橘子', 30)]
? 字典.get(key, value)
取得 key 對應的值,若 key 不存在,則傳回參數中的 value 值
print(dict1.get('鳯梨', 40)) #40
? 字典.setdefault(key, value)
取得key 對應的值,若 key 不存在,則以參數的 key, value 建立新元素,並傳
回 value 值
print(dict1.setdefault('鳯梨', 40)) #40
print(dict1) #{'香蕉': 20, '蘋果': 50, '橘子': 30, '鳯梨': 40}
字典資料處理 2/5
11
dict1 = {'香蕉':20, '蘋果':50, '橘子':30}
? 字典.pop(key[, value])
傳回 key 對應的值,並刪除該元素;如果找不到 key,則回傳 value;如果找
不到 key,又沒指定 value,則會造成 KeyError 異常
print(dict1.pop('蘋果')) #50
print(dict1) #{'香蕉': 20, '橘子': 30}
? 字典.popitem()
傳回最後?筆元素 (元組資料型式),並刪除該元素;如果字典已經為空,卻調
用了此方法,就報出KeyError異常
print(dict1.pop('蘋果')) #('橘子', 30)
print(dict1) #{'香蕉': 20}
? 字典.update(字典2)
以字典2的元素,更新字典
dict1.update({'香蕉':25, '蘋果':50})
print(dict1) #{'香蕉': 25, '蘋果': 50}
字典資料處理 3/5
12
dict1 = {'香蕉':20, '蘋果':50, '橘子':30}
? key in 字典
檢查字典中是否存在key鍵
print('香蕉' in dict1) #True
for key in dict1:
print(key, end = ', ') #香蕉, 蘋果, 橘子,
字典資料處理 4/5
13
sites = {'Google': 'www.google.com', 'Runoob': 'www.runoob.com'}
print(sites.get('Google'))
print(sites.popitem())
print(sites.setdefault('Python', 'www.python.org'))
print(list(sites.keys()))
print(list(sites.values()))
sites.update({'Python':'python.org'})
print(sites.items())
for k in sites:
print(k)
測試結果:
www.google.com
('Runoob', 'www.runoob.com')
www.python.org
['Google', 'Python']
['www.google.com', 'www.python.org']
dict_items([('Google', 'www.google.com'), ('Python', 'python.org')])
Google
Python
字典資料處理 5/5
? 在 Python 不支援其它語言中的 switch 指令,以下程式結合字典物件
與 lambda 函式模擬 switch 指令功能
score = int(input('請輸入分數:'))
level = score // 10
{
10 : lambda: print('Perfect'),
9 : lambda: print('A'),
8 : lambda: print('B'),
7 : lambda: print('C'),
6 : lambda: print('D')
}.get(level, lambda: print('E'))()
測試結果:
請輸入分數:67
D
字典資料應用
? 集合 (Set) 儲存的是無序、元素不重複的資料集
? 集合名稱 = {元素1, 元素2, ...}
programmers = {'Jack', 'Sam', 'Susan', 'Janice'}
? 會重新排列元素順序
? 元素可以是不同資料型別
? set 函式可將串列資料轉換為集合,並自動剔除重複元素
engineers = set(['John', 'Jane', 'Jack', 'Jack', 'Janice'])
? set 函式可將字典資料中的鍵轉換為集合
s = set({1:'A', 2:'B', 3:'C', 4:'D'}) #{1,2,3,4}
? 建立空集合必须用 set() 而不是使用 {} (空字典)
集合資料
16
? 集合.add(x)
將元素 x 添加到集合中,如果元素已存在,則不進行任何操作
? 集合.update(x)
將 x 添加到集合中,x 可以是元素、串列、元組或字典
? 集合.remove(x)
將元素 x 從集合中移除,如果元素不存在,則會發生 KeyError 錯誤
? 集合.discard(x)
將元素 x 從集合中移除,如果元素不存在,則不進行任何操作
? 集合.pop()
取從集合中取出第?個元素,並移除該元素;如果是空集合,則會發生
KeyError 錯誤
? 集合.clear()
清空集合
集合的基本操作 1/3
17
? len(集合)
回傳集合的元素個數
? max(集合)
回傳集合中的最大元素
? min(集合)
回傳集合中的最小元素
? x in 集合
檢查集合中是否存在元素 x
集合的基本操作 2/3
18
programmer = {'Jack', 'Sam', 'Susan', 'Janice'}
programmer.add('Tony')
print(programmer)
programmer.discard('Susan')
print('Susan' in programmer)
print(programmer)
programmer.pop()
print(programmer)
for e in programmer:
print(e)
測試結果:
{'Sam', 'Susan', 'Tony', 'Jack', 'Janice'}
False
{'Sam', 'Tony', 'Jack', 'Janice'}
{'Tony', 'Jack', 'Janice'}
Tony
Jack
Janice
集合的基本操作 3/3
? 交集運算
? 集合1 & 集合2
? 集合1.intersection(集合2)
? 聯集運算
? 集合1 | 集合2
? 集合1.union(集合2)
? 差集運算
? 集合1 – 集合2
? 集合1.difference(集合2)
集合運算 1/3
20
? 對稱差集 (排除相同元素)
? 集合1 ^ 集合2
? 集合1.symmetric_difference(集合2)
? 子集合
? 集合1 < 集合2 #測試s1是否為s2的子集合
? 集合1.issubset(集合2)
? 父集合
? 集合1 > 集合2 #測試s1是否為s2的父集合
? 集合1.issuperset(集合2)
? 判断两集合是否包含相同的元素,如果没有回傳True,否则回傳False
? 集合1.isdisjoint(集合2)
集合運算 2/3
21
engineer = set(['Tony', 'John', 'Jane', 'Jack', 'Janice'])
print(engineer)
programmer = {'Tina', 'Jack', 'Sam', 'Susan', 'Janice', 'Tom'}
manager = set(['Tony', 'Tina', 'Mike'])
employee = engineer | programmer | manager #union
print(employee)
print('engineer and manager:', engineer & manager) #intersection
print('fulltime manager:', manager - engineer - programmer) #difference
engineer.remove('Jane')
print(engineer)
print(len(engineer))
測試結果:
{'John', 'Jane', 'Tony', 'Jack', 'Janice'}
{'Tom', 'Sam', 'John', 'Jane', 'Tony', 'Susan', 'Mike', 'Jack', 'Tina',
'Janice'}
engineer and manager: {'Tony'}
fulltime manager: {'Mike'}
{'John', 'Tony', 'Jack', 'Janice'}
4
集合運算 3/3
? 只有字典提供鍵值索引,而串列、元組及集合這三者極為相似;串列
因為限制少,方便使用但效率會低於其他型別
? 依資料的性質
? 如果資料有兩個以上,且包含唯?的關鍵字,那麼字典是絕佳的選擇
? 如果資料有前後順序的時間因素,或者有可能會重複時,就不能使用集合
? 資料如果有增減的需求,元組就無法達成要求
? 考量資料內建的函式和方法,是否能對資料進行處理
? 集合型別可以有效率的進行聯集、交集等運算
元組、字典和集合使用時機
? sorted() 函式可用來排序任何的 iterable 資料 (string, dictionary,
tuple...),並串列型別回傳排序後之資料
? sorted(iterable, key = None, reverse = False)
? iterable
可迭代運算物件
? key
key 參數的值應該是?個函數,它接受?個參數並返回?個用於排序目的
的鍵。只有當可迭代運算物件的元素為複合資料時,才需
? reverse
排序規則,reverse = True 降冪,reverse = False 昇冪 (預設)
sorted ()函式 1/4
programmers = {'Jack', 'Sam', 'Allen', 'David'}
print(sorted(programmers))
print(sorted(programmers, reverse = True))
fruits = {'apple':23, 'orange':15, 'melon':19}
print(sorted(fruits)) #字典資料預設以key排序
print(sorted(fruits, key = lambda x:fruits[x])) #使用value排序字典資料
測試結果:
['Allen', 'David', 'Jack', 'Sam']
['Sam', 'Jack', 'David', 'Allen']
['apple', 'melon', 'orange']
['orange', 'melon', 'apple']
sorted ()函式 2/4
? 由於經常會用到 key 函式,Python 提供 operator 模組,其中
itemgetter() 函式可以直接做為 key 函式
fruits = {'apple':23, 'orange':15, 'melon':19}
print(sorted(fruits, key = itemgetter(0))) #使用key排序字典資料
print(sorted(fruits, key = itemgetter(1))) #使用value排序字典資料
students = [('Bill', 'B', 15), ('Danny', 'A', 14), ('Geoff', 'B', 14)]
print(sorted(students))
print(sorted(students, key = lambda x:x[1])) #以成績排序資料
print(sorted(students, key = itemgetter(1))) #以成績排序資料
print(sorted(students, key = lambda x:(x[1], x[2]))) #先以成績再以年齡排序資料
print(sorted(students, key = itemgetter(1, 2))) #先以成績再以年齡排序資料
測試結果:
['apple', 'melon', 'orange']
['melon', 'apple', 'orange']
[('Bill', 'B', 15), ('Danny', 'A', 14), ('Geoff', 'B', 14)]
[('Danny', 'A', 14), ('Bill', 'B', 15), ('Geoff', 'B', 14)]
[('Danny', 'A', 14), ('Bill', 'B', 15), ('Geoff', 'B', 14)]
[('Danny', 'A', 14), ('Geoff', 'B', 14), ('Bill', 'B', 15)]
[('Danny', 'A', 14), ('Geoff', 'B', 14), ('Bill', 'B', 15)]
sorted ()函式 3/4
? 如果要排序的物件是class object的話,也可以使用operator模組中的
attrgetter() 做為 key 函式
class Student:
def __init__(self, name, grade, age):
self.name = name
self.grade = grade
self.age = age
def __repr__(self):
return repr((self.name, self.grade, self.age))
students = [Student('Bill', 'B', 15), Student('Danny', 'A', 14),
Student('Geoff', 'B', 14)]
print(sorted(students, key = attrgetter('grade'))) #比成績
print(sorted(students, key = attrgetter('grade', 'age'))) #先比成績再比年齡
測試結果:
[('Danny', 'A', 14), ('Bill', 'B', 15), ('Geoff', 'B', 14)]
[('Danny', 'A', 14), ('Geoff', 'B', 14), ('Bill', 'B', 15)]
註:有關類別宣告後續單元再介紹
sorted ()函式 4/4
? enumerate() 函式用來自可叠代對象 (如串列、元組、集合等) 中依序
列舉出元素值,並加以順序編號
? enumerate(sequence, [start = 0])
? start 為將列舉所取得資料進行編號之起始值,預設值為 0
? enumerate 多用於在 for 循環中得到計數,利用它可以同時獲得索引
和值,即需要 index 和 value 值的時候可以使用
programmer = {'Jack', 'Sam', 'Susan', 'Janice'}
for index, name in enumerate(programmer, start = 1):
print('%s. %s' %(index, name))
測試結果:
1. Susan
2. Sam
3. Janice
4. Jack
enumerate()函式
? 遊戲規則
? 由玩家 (X) 與電腦 (O) 輪流對奕,隨機決定先手
? 先連成?線者勝出
? 電腦落子策略
1. 檢查棋盤,如有決勝點即落子
2. 檢查棋盤,如存在對手決勝點,落子阻斷
3. 依據棋盤空格優先序落子
1) 四個角落空格
2) 中間空格
3) 四個邊空格
應用實例:井字棋遊戲 1/8
? 建立board串列儲存對奕資料,元素 1 ~元素 9 對應井字棋盤九格,元
素 0 沒使用;'X'表示玩家落子,'O'表示電腦落子,' '表示空格
import random
board = [' ' for x in range(10)]
? printBoard() 自訂函式用來顯示井字棋
def printBoard():
print(' ' + board[1] + '|' + board[2] + '|' + board[3] + ' ')
print('--+-+--')
print(' ' + board[4] + '|' + board[5] + '|' + board[6] + ' ')
print('--+-+--')
print(' ' + board[7] + '|' + board[8] + '|' + board[9] + ' ')
應用實例:井字棋遊戲 2/8
1 2 3
4 5 6
7 8 9
? isWinner(bo, c)自訂函式用來檢查是否連線,有連線時回傳 True
? bo 井字棋對奕資料
? c 為棋子符號,'X'代表玩家,'O'代表電腦
def isWinner(bo, c):
return (bo[1]==bo[2]==bo[3]==c) or (bo[4]==bo[5]==bo[6]==c) or 
(bo[7]==bo[8]==bo[9]==c) or (bo[1]==bo[4]==bo[7]==c) or 
(bo[2]==bo[5]==bo[8]==c) or (bo[3]==bo[6]==bo[9]==c) or 
(bo[1]==bo[5]==bo[9]==c) or (bo[3]==bo[5]==bo[7]==c)
? isBoardFull(bo)自訂函式用來檢查井字棋是否填滿了
def isBoardFull():
return board.count(' ') == 1 #只剩?個空格時(元素0),表示棋盤已填滿
? selectRandom(li)自訂函式用來自li串列中隨機挑選?個元素值
def selectRandom(li):
r = random.randrange(0, len(li))
return li[r]
應用實例:井字棋遊戲 3/8
? playerTurn()自訂函式為玩家回合處理作業,若玩家輸入的棋盤位
置編號為空格則落子'X',否則重新輸入
def playerTurn():
while True:
try:
move = int(input('Select a position to place an 'X' (1-9): '))
if move > 0 and move < 10:
if (board[move] == ' '):
board[move] = 'X'
break
else:
print('Sorry, this space is occupied!')
else:
print('Please type a number within the range!')
except:
print('Please type a number!')
printBoard() #顯示棋盤目前結果
應用實例:井字棋遊戲 4/8
1 2 3
4 5 6
7 8 9
? evaluateMove()自訂函式為電腦回合計算最佳落子位置
? 落子優先序:連線決勝點、阻斷對手連線點、四個角落、中間、四個邊
def evaluateMove():
candiate = tuple([x for x, c in enumerate(board) if c == ' ' and x != 0])
for let in ('O', 'X'): #檢查決勝點及阻斷對手決勝點
for i in candiate :
boardCopy = board[:] #複製棋盤以便測試
boardCopy[i] = let
if isWinner(boardCopy, let):
return i
cornersOpen = []
for i in candiate :
if i in (1, 3, 7, 9):
cornersOpen.append(i)
if len(cornersOpen) > 0: #選擇四個角落位置
return selectRandom(cornersOpen)
應用實例:井字棋遊戲 5/8
if 5 in candiate: #選擇中間位置
return 5
edgesOpen = []
for i in candiate:
if i in (2, 4, 6, 8):
edgesOpen.append(i)
if len(edgesOpen) > 0: #選擇四邊位置
return selectRandom(edgesOpen)
? computerTurn()自訂函式為電腦回合處理作業
def computerTurn():
move = evaluateMove()
board[move] = 'O'
print('Computer placed an 'O' in position', move)
printBoard() #顯示棋盤目前結果
應用實例:井字棋遊戲 6/8
? game()自訂函式為遊戲流程控制作業
def game(turn):
while True:
if (turn):
playerTurn() #玩家回合
turn = 1 - turn #換手
if isWinner(board, 'X'):
print('You won this time!')
break;
else:
computerTurn() #電腦回合
turn = 1 - turn #換手
if isWinner(board, 'O'):
print('Computer won this time!')
break;
if isBoardFull():
print('Tie Game!')
break;
應用實例:井字棋遊戲 7/8
? 程式主流程
while True:
print('Welcome to Tic Tac Toe!', end = ', ')
turn = random.randint(0, 9) % 2 #隨機決定先手,0電腦, 1玩家
if (turn == 1):
print('玩家先下')
printBoard() #畫出空棋盤
else:
print('電腦先下')
game(turn)
answer = input('Do you want to play again? (Y/N)')
if answer.lower() == 'y' or answer.lower == 'yes':
board = [' ' for x in range(10)]
print('-----------------------------------')
else:
break
應用實例:井字棋遊戲 8/8

More Related Content

笔测迟丑辞苍元组,字典,集合

  • 1. 笔测迟丑辞苍元组,字典,集合 Revised on August 26, 2021 ? Python的資料結構 ? 元組資料與應用 ? 字典資料與應用 ? 集合資料與應用 ? 使用sorted()函式 ? 使用enumerate()函式 ? 應用實例 – 井字棋遊戲
  • 2. ? Python 支援四種資料結構:list、tuple、set及dictionary,而且彼此 問可以相互轉換 ? 串列類似其它程式語言的陣列 (Array),但Python 串列中的元素允許 是不同資料型別 list1 = ['apple', 23, 'orange', 15, 'melon', 19] ? 元組 (tuple) 類似串列,但建立資料後,內容就不可變更 tuple1 = ('apple', 23, 'orange', 15, 'melon', 19) ? 集合 (set) 為不重複的非排序元素集,可進行數學上的集合運算 set1 = {'apple', 23, 'orange', 15, 'melon', 19} ? 字典 (dictionary) 用於儲存由 key 索引的鍵?值配對 (Key-Value Pair) 資料,鍵必須是唯? dict1 = {'apple':23, 'orange':15, 'melon':19} Python的資料結構 2
  • 3. ? 元組 (tuple) 類似串列,元組的元素可以由不同型別的資料型別來組成, 但元組建立後元素個數及內容都不可變更 ? 讀取元組內的元素時,使用的註標即建立時的順序,運算速度最快 ? 元組的宣告 ? 元組變數 = 元素A, 元素B, 元素C, ... ? 元組變數 = (元素A, 元素B, 元素C, ...) tuple1 = () #宣告空元組 dummy1 = 65 #整數資料 tuple2 = 65, #宣告只有?個元素的元組,元素之後必須加上逗號 dummy2 = (65) #整數資料 tuple3 = (65,) #宣告只有?個元素的元組,元素之後必須加上逗號 tuple4 = (65, 'A') #元素可以是不同資料型別 print(tuple4[1]) #A 元組資料 1/2
  • 4. ? list 函式可將元組資料轉換為串列 mytuple = (1, 2, 3, 4, 5) list1 = list(mytuple) ? tuple 函式可將串列資料轉換為元組 mylist = [1, 2, 3, 4, 5] tuple1 = tuple(mylist) 元組資料 2/2 4
  • 5. tuple1 = ('apple', 23, 'orange', 15, 'melon', 19) tuple2 = (7, 20, 15, 40, 19.5) ? value in 元組 檢查元組中是否存在value元素值 print(50 in tuple1) #False ? 元組[i] 回傳註標為i的元素值 print(tuple2[0]) #apple ? len(元組) 取得元組元素數目 print(len(tuple1)) #6 ? min(元組) 取得元組中最小的元素值,只適用於元素皆為數值資料之元組 print(min(tuple2)) #7 元組的基本操作 1/2
  • 6. ? max(元組) 取得元組中最大的元素值,只適用於元素皆為數值資料之元組 print(max(tuple2)) #40 ? sum(元組) 計算元組元素的總和,只適用於元素皆為數值資料之元組 print(sum(tuple2)) #101.5 tuple1 = ('apple', 23, 'orange', 15, 'melon', 19) tuple1[1] = 25 #錯誤 元組的基本操作 2/2 TypeError: 'tuple' object does not support item assignment
  • 7. ? 字典資料 (dict) 的元素由「鍵(Key):值(Value)」組成,元素間用逗號 分隔,所有元素被 {} 大括號包圍 ? 字典 = {鍵1:值1, 鍵2:值2, ...} ? 鍵必須是唯?,如果鍵值重覆,前?鍵值的元素會被後?鍵值的元素覆 蓋。鍵可以使用數值、字串或元組 ? 值可以是任何資料型別 dict1 = {'香蕉':20, '蘋果':50, '橘子':30} dict2 = dict(?瓜 = 30, 葡萄 = 45, 百香果 = 60) print(dict1) print(dict2) 測試結果: {'香蕉': 20, '蘋果': 50, '橘子': 30} {'?瓜': 30, '葡萄': 45, '百香果': 60} 字典資料 7
  • 8. dict1 = {'香蕉':20, '蘋果':50, '橘子':30} ? 字典[key] = value 在字典新增key:value元素,若已存在鍵,表示更新值 dict1['鳯梨'] = 40 ? del 字典[key] 刪除字典中鍵為 key 的元素 del dict1['鳯梨'] ? 字典.clear() 可刪除字典的所有元素 dict1.clear() ? del 字典 刪除整個字典資料 del dict1 字典資料維護 1/2 8
  • 9. dict1 = {'香蕉':20, '蘋果':50, '橘子':30} dict1['鳯梨'] = 40 print(dict1) #{'香蕉':20, '蘋果':50, '橘子':30, '鳯梨':40} del dict1['蘋果'] print(dict1) #{'香蕉':20, '橘子':30, '鳯梨':40} dict1.clear() print(dict1) #{} del dict1 print(dict1) #錯誤 字典資料維護 2/2 NameError: name 'dict1' is not defined
  • 10. dict1 = {'香蕉':20, '蘋果':50, '橘子':30} ? len(字典) 計算字典的元素個數 print(len(dict1)) #3 ? 字典.fromkeys(元組或串列[, 預設值]) 以元組或串列元素為鍵,建立字典,如有重複元素會自動去除 fruits = ('apple', 'orange', 'melon') fruitdic = {}.fromkeys(fruits, 30) print(fruitdic) #{'apple': 30, 'orange': 30, 'melon': 30} ? 字典.keys() 傳回字典中所有的鍵,傳回資料可用 list 函式轉換為串列 print(list(dict1.keys())) #['香蕉', '蘋果', '橘子'] ? 字典.values() 傳回字典中所有的值,傳回資料可用 list 函式轉換為串列 print(list(sites. values())) #[20, 50, 30] 字典資料處理 1/5 10
  • 11. dict1 = {'香蕉':20, '蘋果':50, '橘子':30} ? 字典.items() 傳回字典中所有的元素,每?對鍵值會形成?個元組。傳回資料可用 list 函式 轉換為串列 print(list(dict1.items())) #[('香蕉', 20), ('蘋果', 50), ('橘子', 30)] ? 字典.get(key, value) 取得 key 對應的值,若 key 不存在,則傳回參數中的 value 值 print(dict1.get('鳯梨', 40)) #40 ? 字典.setdefault(key, value) 取得key 對應的值,若 key 不存在,則以參數的 key, value 建立新元素,並傳 回 value 值 print(dict1.setdefault('鳯梨', 40)) #40 print(dict1) #{'香蕉': 20, '蘋果': 50, '橘子': 30, '鳯梨': 40} 字典資料處理 2/5 11
  • 12. dict1 = {'香蕉':20, '蘋果':50, '橘子':30} ? 字典.pop(key[, value]) 傳回 key 對應的值,並刪除該元素;如果找不到 key,則回傳 value;如果找 不到 key,又沒指定 value,則會造成 KeyError 異常 print(dict1.pop('蘋果')) #50 print(dict1) #{'香蕉': 20, '橘子': 30} ? 字典.popitem() 傳回最後?筆元素 (元組資料型式),並刪除該元素;如果字典已經為空,卻調 用了此方法,就報出KeyError異常 print(dict1.pop('蘋果')) #('橘子', 30) print(dict1) #{'香蕉': 20} ? 字典.update(字典2) 以字典2的元素,更新字典 dict1.update({'香蕉':25, '蘋果':50}) print(dict1) #{'香蕉': 25, '蘋果': 50} 字典資料處理 3/5 12
  • 13. dict1 = {'香蕉':20, '蘋果':50, '橘子':30} ? key in 字典 檢查字典中是否存在key鍵 print('香蕉' in dict1) #True for key in dict1: print(key, end = ', ') #香蕉, 蘋果, 橘子, 字典資料處理 4/5 13
  • 14. sites = {'Google': 'www.google.com', 'Runoob': 'www.runoob.com'} print(sites.get('Google')) print(sites.popitem()) print(sites.setdefault('Python', 'www.python.org')) print(list(sites.keys())) print(list(sites.values())) sites.update({'Python':'python.org'}) print(sites.items()) for k in sites: print(k) 測試結果: www.google.com ('Runoob', 'www.runoob.com') www.python.org ['Google', 'Python'] ['www.google.com', 'www.python.org'] dict_items([('Google', 'www.google.com'), ('Python', 'python.org')]) Google Python 字典資料處理 5/5
  • 15. ? 在 Python 不支援其它語言中的 switch 指令,以下程式結合字典物件 與 lambda 函式模擬 switch 指令功能 score = int(input('請輸入分數:')) level = score // 10 { 10 : lambda: print('Perfect'), 9 : lambda: print('A'), 8 : lambda: print('B'), 7 : lambda: print('C'), 6 : lambda: print('D') }.get(level, lambda: print('E'))() 測試結果: 請輸入分數:67 D 字典資料應用
  • 16. ? 集合 (Set) 儲存的是無序、元素不重複的資料集 ? 集合名稱 = {元素1, 元素2, ...} programmers = {'Jack', 'Sam', 'Susan', 'Janice'} ? 會重新排列元素順序 ? 元素可以是不同資料型別 ? set 函式可將串列資料轉換為集合,並自動剔除重複元素 engineers = set(['John', 'Jane', 'Jack', 'Jack', 'Janice']) ? set 函式可將字典資料中的鍵轉換為集合 s = set({1:'A', 2:'B', 3:'C', 4:'D'}) #{1,2,3,4} ? 建立空集合必须用 set() 而不是使用 {} (空字典) 集合資料 16
  • 17. ? 集合.add(x) 將元素 x 添加到集合中,如果元素已存在,則不進行任何操作 ? 集合.update(x) 將 x 添加到集合中,x 可以是元素、串列、元組或字典 ? 集合.remove(x) 將元素 x 從集合中移除,如果元素不存在,則會發生 KeyError 錯誤 ? 集合.discard(x) 將元素 x 從集合中移除,如果元素不存在,則不進行任何操作 ? 集合.pop() 取從集合中取出第?個元素,並移除該元素;如果是空集合,則會發生 KeyError 錯誤 ? 集合.clear() 清空集合 集合的基本操作 1/3 17
  • 18. ? len(集合) 回傳集合的元素個數 ? max(集合) 回傳集合中的最大元素 ? min(集合) 回傳集合中的最小元素 ? x in 集合 檢查集合中是否存在元素 x 集合的基本操作 2/3 18
  • 19. programmer = {'Jack', 'Sam', 'Susan', 'Janice'} programmer.add('Tony') print(programmer) programmer.discard('Susan') print('Susan' in programmer) print(programmer) programmer.pop() print(programmer) for e in programmer: print(e) 測試結果: {'Sam', 'Susan', 'Tony', 'Jack', 'Janice'} False {'Sam', 'Tony', 'Jack', 'Janice'} {'Tony', 'Jack', 'Janice'} Tony Jack Janice 集合的基本操作 3/3
  • 20. ? 交集運算 ? 集合1 & 集合2 ? 集合1.intersection(集合2) ? 聯集運算 ? 集合1 | 集合2 ? 集合1.union(集合2) ? 差集運算 ? 集合1 – 集合2 ? 集合1.difference(集合2) 集合運算 1/3 20
  • 21. ? 對稱差集 (排除相同元素) ? 集合1 ^ 集合2 ? 集合1.symmetric_difference(集合2) ? 子集合 ? 集合1 < 集合2 #測試s1是否為s2的子集合 ? 集合1.issubset(集合2) ? 父集合 ? 集合1 > 集合2 #測試s1是否為s2的父集合 ? 集合1.issuperset(集合2) ? 判断两集合是否包含相同的元素,如果没有回傳True,否则回傳False ? 集合1.isdisjoint(集合2) 集合運算 2/3 21
  • 22. engineer = set(['Tony', 'John', 'Jane', 'Jack', 'Janice']) print(engineer) programmer = {'Tina', 'Jack', 'Sam', 'Susan', 'Janice', 'Tom'} manager = set(['Tony', 'Tina', 'Mike']) employee = engineer | programmer | manager #union print(employee) print('engineer and manager:', engineer & manager) #intersection print('fulltime manager:', manager - engineer - programmer) #difference engineer.remove('Jane') print(engineer) print(len(engineer)) 測試結果: {'John', 'Jane', 'Tony', 'Jack', 'Janice'} {'Tom', 'Sam', 'John', 'Jane', 'Tony', 'Susan', 'Mike', 'Jack', 'Tina', 'Janice'} engineer and manager: {'Tony'} fulltime manager: {'Mike'} {'John', 'Tony', 'Jack', 'Janice'} 4 集合運算 3/3
  • 23. ? 只有字典提供鍵值索引,而串列、元組及集合這三者極為相似;串列 因為限制少,方便使用但效率會低於其他型別 ? 依資料的性質 ? 如果資料有兩個以上,且包含唯?的關鍵字,那麼字典是絕佳的選擇 ? 如果資料有前後順序的時間因素,或者有可能會重複時,就不能使用集合 ? 資料如果有增減的需求,元組就無法達成要求 ? 考量資料內建的函式和方法,是否能對資料進行處理 ? 集合型別可以有效率的進行聯集、交集等運算 元組、字典和集合使用時機
  • 24. ? sorted() 函式可用來排序任何的 iterable 資料 (string, dictionary, tuple...),並串列型別回傳排序後之資料 ? sorted(iterable, key = None, reverse = False) ? iterable 可迭代運算物件 ? key key 參數的值應該是?個函數,它接受?個參數並返回?個用於排序目的 的鍵。只有當可迭代運算物件的元素為複合資料時,才需 ? reverse 排序規則,reverse = True 降冪,reverse = False 昇冪 (預設) sorted ()函式 1/4
  • 25. programmers = {'Jack', 'Sam', 'Allen', 'David'} print(sorted(programmers)) print(sorted(programmers, reverse = True)) fruits = {'apple':23, 'orange':15, 'melon':19} print(sorted(fruits)) #字典資料預設以key排序 print(sorted(fruits, key = lambda x:fruits[x])) #使用value排序字典資料 測試結果: ['Allen', 'David', 'Jack', 'Sam'] ['Sam', 'Jack', 'David', 'Allen'] ['apple', 'melon', 'orange'] ['orange', 'melon', 'apple'] sorted ()函式 2/4
  • 26. ? 由於經常會用到 key 函式,Python 提供 operator 模組,其中 itemgetter() 函式可以直接做為 key 函式 fruits = {'apple':23, 'orange':15, 'melon':19} print(sorted(fruits, key = itemgetter(0))) #使用key排序字典資料 print(sorted(fruits, key = itemgetter(1))) #使用value排序字典資料 students = [('Bill', 'B', 15), ('Danny', 'A', 14), ('Geoff', 'B', 14)] print(sorted(students)) print(sorted(students, key = lambda x:x[1])) #以成績排序資料 print(sorted(students, key = itemgetter(1))) #以成績排序資料 print(sorted(students, key = lambda x:(x[1], x[2]))) #先以成績再以年齡排序資料 print(sorted(students, key = itemgetter(1, 2))) #先以成績再以年齡排序資料 測試結果: ['apple', 'melon', 'orange'] ['melon', 'apple', 'orange'] [('Bill', 'B', 15), ('Danny', 'A', 14), ('Geoff', 'B', 14)] [('Danny', 'A', 14), ('Bill', 'B', 15), ('Geoff', 'B', 14)] [('Danny', 'A', 14), ('Bill', 'B', 15), ('Geoff', 'B', 14)] [('Danny', 'A', 14), ('Geoff', 'B', 14), ('Bill', 'B', 15)] [('Danny', 'A', 14), ('Geoff', 'B', 14), ('Bill', 'B', 15)] sorted ()函式 3/4
  • 27. ? 如果要排序的物件是class object的話,也可以使用operator模組中的 attrgetter() 做為 key 函式 class Student: def __init__(self, name, grade, age): self.name = name self.grade = grade self.age = age def __repr__(self): return repr((self.name, self.grade, self.age)) students = [Student('Bill', 'B', 15), Student('Danny', 'A', 14), Student('Geoff', 'B', 14)] print(sorted(students, key = attrgetter('grade'))) #比成績 print(sorted(students, key = attrgetter('grade', 'age'))) #先比成績再比年齡 測試結果: [('Danny', 'A', 14), ('Bill', 'B', 15), ('Geoff', 'B', 14)] [('Danny', 'A', 14), ('Geoff', 'B', 14), ('Bill', 'B', 15)] 註:有關類別宣告後續單元再介紹 sorted ()函式 4/4
  • 28. ? enumerate() 函式用來自可叠代對象 (如串列、元組、集合等) 中依序 列舉出元素值,並加以順序編號 ? enumerate(sequence, [start = 0]) ? start 為將列舉所取得資料進行編號之起始值,預設值為 0 ? enumerate 多用於在 for 循環中得到計數,利用它可以同時獲得索引 和值,即需要 index 和 value 值的時候可以使用 programmer = {'Jack', 'Sam', 'Susan', 'Janice'} for index, name in enumerate(programmer, start = 1): print('%s. %s' %(index, name)) 測試結果: 1. Susan 2. Sam 3. Janice 4. Jack enumerate()函式
  • 29. ? 遊戲規則 ? 由玩家 (X) 與電腦 (O) 輪流對奕,隨機決定先手 ? 先連成?線者勝出 ? 電腦落子策略 1. 檢查棋盤,如有決勝點即落子 2. 檢查棋盤,如存在對手決勝點,落子阻斷 3. 依據棋盤空格優先序落子 1) 四個角落空格 2) 中間空格 3) 四個邊空格 應用實例:井字棋遊戲 1/8
  • 30. ? 建立board串列儲存對奕資料,元素 1 ~元素 9 對應井字棋盤九格,元 素 0 沒使用;'X'表示玩家落子,'O'表示電腦落子,' '表示空格 import random board = [' ' for x in range(10)] ? printBoard() 自訂函式用來顯示井字棋 def printBoard(): print(' ' + board[1] + '|' + board[2] + '|' + board[3] + ' ') print('--+-+--') print(' ' + board[4] + '|' + board[5] + '|' + board[6] + ' ') print('--+-+--') print(' ' + board[7] + '|' + board[8] + '|' + board[9] + ' ') 應用實例:井字棋遊戲 2/8 1 2 3 4 5 6 7 8 9
  • 31. ? isWinner(bo, c)自訂函式用來檢查是否連線,有連線時回傳 True ? bo 井字棋對奕資料 ? c 為棋子符號,'X'代表玩家,'O'代表電腦 def isWinner(bo, c): return (bo[1]==bo[2]==bo[3]==c) or (bo[4]==bo[5]==bo[6]==c) or (bo[7]==bo[8]==bo[9]==c) or (bo[1]==bo[4]==bo[7]==c) or (bo[2]==bo[5]==bo[8]==c) or (bo[3]==bo[6]==bo[9]==c) or (bo[1]==bo[5]==bo[9]==c) or (bo[3]==bo[5]==bo[7]==c) ? isBoardFull(bo)自訂函式用來檢查井字棋是否填滿了 def isBoardFull(): return board.count(' ') == 1 #只剩?個空格時(元素0),表示棋盤已填滿 ? selectRandom(li)自訂函式用來自li串列中隨機挑選?個元素值 def selectRandom(li): r = random.randrange(0, len(li)) return li[r] 應用實例:井字棋遊戲 3/8
  • 32. ? playerTurn()自訂函式為玩家回合處理作業,若玩家輸入的棋盤位 置編號為空格則落子'X',否則重新輸入 def playerTurn(): while True: try: move = int(input('Select a position to place an 'X' (1-9): ')) if move > 0 and move < 10: if (board[move] == ' '): board[move] = 'X' break else: print('Sorry, this space is occupied!') else: print('Please type a number within the range!') except: print('Please type a number!') printBoard() #顯示棋盤目前結果 應用實例:井字棋遊戲 4/8 1 2 3 4 5 6 7 8 9
  • 33. ? evaluateMove()自訂函式為電腦回合計算最佳落子位置 ? 落子優先序:連線決勝點、阻斷對手連線點、四個角落、中間、四個邊 def evaluateMove(): candiate = tuple([x for x, c in enumerate(board) if c == ' ' and x != 0]) for let in ('O', 'X'): #檢查決勝點及阻斷對手決勝點 for i in candiate : boardCopy = board[:] #複製棋盤以便測試 boardCopy[i] = let if isWinner(boardCopy, let): return i cornersOpen = [] for i in candiate : if i in (1, 3, 7, 9): cornersOpen.append(i) if len(cornersOpen) > 0: #選擇四個角落位置 return selectRandom(cornersOpen) 應用實例:井字棋遊戲 5/8
  • 34. if 5 in candiate: #選擇中間位置 return 5 edgesOpen = [] for i in candiate: if i in (2, 4, 6, 8): edgesOpen.append(i) if len(edgesOpen) > 0: #選擇四邊位置 return selectRandom(edgesOpen) ? computerTurn()自訂函式為電腦回合處理作業 def computerTurn(): move = evaluateMove() board[move] = 'O' print('Computer placed an 'O' in position', move) printBoard() #顯示棋盤目前結果 應用實例:井字棋遊戲 6/8
  • 35. ? game()自訂函式為遊戲流程控制作業 def game(turn): while True: if (turn): playerTurn() #玩家回合 turn = 1 - turn #換手 if isWinner(board, 'X'): print('You won this time!') break; else: computerTurn() #電腦回合 turn = 1 - turn #換手 if isWinner(board, 'O'): print('Computer won this time!') break; if isBoardFull(): print('Tie Game!') break; 應用實例:井字棋遊戲 7/8
  • 36. ? 程式主流程 while True: print('Welcome to Tic Tac Toe!', end = ', ') turn = random.randint(0, 9) % 2 #隨機決定先手,0電腦, 1玩家 if (turn == 1): print('玩家先下') printBoard() #畫出空棋盤 else: print('電腦先下') game(turn) answer = input('Do you want to play again? (Y/N)') if answer.lower() == 'y' or answer.lower == 'yes': board = [' ' for x in range(10)] print('-----------------------------------') else: break 應用實例:井字棋遊戲 8/8