Tuples
Introduction
有了上一章的基礎後,我相信序對(Tuple)對你來說不會困難,因為它跟串列(List)很像,只是它是用小括號()
來表示,而且它是不可變的(immutable)。這表示你不能新增、刪除或修改裡面的元素。那既然如此,為什麼還要用它呢?
Create a Tuple
要建立一個序對有很多種方法,最簡單的就是用小括號()
把元素包起來,用逗號,
隔開就好了。
但在下面的例子中,你會發現,只有一個元素時,你必須在後面加上逗號。這邊你自己試試看,應該都能理解。
| empty = ()
one = (1,)
two = (1, 2)
print(len(empty), len(one), len(two))
print(type(empty))
odd = 1, 3, 5
print(odd)
print(type(odd))
|
Output |
---|
| 0 1 2
<class 'tuple'>
(1, 3, 5)
(1, 3, 5)
<class 'tuple'>
|
你也可以用tuple()
來建立一個序對,直接看例子:
| lst = [1, 2, 3, 4, 5]
tup = tuple(lst)
print(tup)
s = "know me..."
s_tup = tuple(s)
print(s_tup)
|
Output |
---|
| (1, 2, 3, 4, 5)
('k', 'n', 'o', 'w', ' ', 'm', 'e', '.', '.', '.')
|
八木海莉 『know me...』
還記得 List Comprehension 嗎?我們將中括號改成小括號試試看:
| gen = (x ** 2 for x in range(5))
print(type(gen))
tup = tuple(gen)
print(tup)
|
Output |
---|
| <class 'generator'>
(0, 1, 4, 9, 16)
|
你會發現,結果並非是你預期的序對,而是產生器(Generator),你還需要使用tuple()
來轉換。
至於為什麼要用產生器(Generator),我會在未來的章節跟你說明,又挖坑了。
那麼加法跟乘法呢?跟串列(List)一樣,你可以用加法來合併兩個序對,用乘法來複製序對。
| a = (1, 2, 3)
b = 4, 5, 6
c = a + b
print(c)
d = a * 2 + b
print(d)
|
Output |
---|
| (1, 2, 3, 4, 5, 6)
(1, 2, 3, 1, 2, 3, 4, 5, 6)
|
Operations
Accessing elements
跟串列(List)一樣,你可以用索引來存取序對中的元素,也可以用負索引來從後存取。
| t = (1, 2, 3, 4, 5)
print(t[0], t[-1])
|
Slicing
同樣的,你也可以用切片來取得序對中的子序對。
| t = (1, 2, 3, 4, 5)
print(t[1:3])
print(t[:3])
print(t[3:])
print(t[:])
|
Output |
---|
| (2, 3)
(1, 2, 3)
(4, 5)
(1, 2, 3, 4, 5)
|
Modifying elements
但是你不能修改序對中的元素,這是不可變的(immutable),是有折衷的方法啦,就是把序對轉換成串列,再轉換回來。
| cat_tup = ("😸", "😺", "😻", ["😿", "🙀"])
cat_lst = list(cat_tup)
cat_lst[1] = "😼"
cat_tup = tuple(cat_lst)
print(cat_tup)
cat_tup[3][0] = "😾"
print(cat_tup)
cat_tup[1] = "😽"
print(cat_tup)
|
Output |
---|
| ('😸', '😼', '😻', ['😿', '🙀'])
('😸', '😼', '😻', ['😾', '🙀'])
TypeError: 'tuple' object does not support item assignment
|
但你有沒有覺得怪怪的,為什麼我可以修改序對中的串列呢?
Checking elements
你可以用 in
來檢查元素是否在序對中,這跟串列是一樣的。
| fib = (0, 1, 1, 2, 3, 5, 8)
print(0 not in fib)
print(5 in fib)
|
Question
對於長度為 \(n\) 的無序序對,要檢查某個元素是否存在於序對中,最好的情況下,需要檢查多少次?
又是熟悉的問題,你可以的。
Methods
因為序對是不可變的(immutable),所以只有兩個方法,一個是count()
,一個是index()
,你可以自己試試看。
count
count()
會回傳括號內的元素在序對中出現的次數,當然 List 也有這個方法,但前面我並沒有提,因為可以放在這裡水內容(X
| t = ((1, 2), (3, 4), 6, 6, [7, 8])
print(t.count(1))
print(t.count([7, 8]))
print(t.count(6))
|
index
index()
會回傳括號內的元素在序對中的索引,一樣的,List 也有這個方法。
| t = ("Love Me Again", "John Newman", 2013)
print(t.index("John Newman"))
print(t.index(2014))
|
Output |
---|
| 1
ValueError: tuple.index(x): x not in tuple
|
John Newman - Love Me Again
Tuple vs List
- List
- 用中括號
[]
表示
- 可變的(mutable)
- 不可雜湊(unhashable)
- 效能較差
- 適用於頻繁的增刪改
- Tuple
- 用小括號
()
表示
- 不可變的(immutable)
- 可雜湊(hashable)
- 效能較好
- 適用於不需要變動的資料,例如常數、座標
關於「可雜湊的(hashable)」,我會在字典(Dict)這章中跟你說明。
Practice
Reference code
| N = int(input())
dirs = ((0, 1), (0, -1), (1, 0), (-1, 0))
for k in range(N):
n, m = map(int, input().split())
pic = []
for _ in range(n):
pic.append(input().split())
for i in range(n):
for j in range(m):
if pic[i][j] == '0':
print('_ ', end='')
else:
is_edge = False
for d in dirs:
x, y = i + d[0], j + d[1]
if 0 <= x < n and 0 <= y < m and pic[x][y] == '0':
is_edge = True
break
if is_edge:
print('0 ', end='')
else:
print('_ ', end='')
print()
if k != N - 1:
print()
|
方向 dirs
就很適用序對來表示,因為它是固定的,不會變動。
未來在學圖形走訪的時候,你會一直看到這種寫法。
對了, 迴圈變數 _
被稱為捨棄變數,表示不需要用到這個變數,只是為了配合迴圈語法而已。
Assignment
@EditTime : 2024-02-04 21:15