串列 List
串列可以一次存放一整排資料,用中括號 [] 框起來、逗號隔開。它是 Python 裡最常用的資料結構。
串列裡的每個位置都有一個索引,從 0 開始算。用 串列[索引] 取出某個位置的值,也能指定新值蓋過去:
fruits = ["蘋果", "香蕉", "橘子", "西瓜"]
print(fruits[0])print(fruits[2])print(fruits[-1])
fruits[1] = "芒果"print(fruits)索引也可以是負的,-1 是最後一個、-2 是倒數第二個,從尾巴往回數很方便。
用 串列[開始:結束] 可以一次取出一段,同樣是「取到結束的前一個」為止:
numbers = [10, 20, 30, 40, 50]
print(numbers[1:4])print(numbers[:3])print(numbers[2:])冒號前後可以省略:[:3] 是從頭到第 3 個之前,[2:] 是從第 2 個到最後。
切片還能加上第三個數字當「間隔」,寫成 [開始:結束:間隔]。間隔設成 -1 是最常用的技巧,可以把整個串列反過來:
nums = [1, 2, 3, 4, 5, 6]
print(nums[::-1])print(nums[::2])[::-1] 從頭到尾、間隔 -1,就是反轉;[::2] 則是每隔一個取一個。
串列有很多內建的方法,這裡列幾個最常用的:
numbers = [3, 1, 4, 1, 5]
numbers.append(9)numbers.sort()
print(numbers)print(len(numbers))print(4 in numbers)append(x):在尾巴加一個元素。sort():把串列由小到大排序(直接改動原本的串列)。len(串列):算長度,也就是有幾個元素。x in 串列:檢查x在不在串列裡,回傳True或False。
還有更多常用的方法:
nums = [3, 1, 4, 1, 5]
print(nums.index(4))print(nums.index(1, 2))print(nums.count(1))
nums.insert(0, 9)print(nums)
nums.pop()print(nums)
nums.reverse()print(nums)
nums.extend([7, 8])print(nums)index(x):找出x第一次出現的位置。加第二個參數index(x, 開始),就從指定位置往後找,可以用來找第二個、第三個。count(x):數x出現幾次。insert(位置, x):把x插到指定位置。pop():取出並移除最後一個(放進括號指定位置也可以)。reverse():把整個串列前後顛倒(直接改動原串列)。extend(另一個串列):把另一個串列的元素全接到後面。
append 和 extend 很容易搞混,兩個都是往後面加,差在怎麼加。append 一次加一個:丟一個串列進去,它就整包變成裡面的一個元素;extend 則把那個串列拆開,元素一個一個接上去:
a = [1, 2, 3]a.append([4, 5])print(a)
b = [1, 2, 3]b.extend([4, 5])print(b)所以 a.append([4, 5]) 之後,[4, 5] 變成 a 裡的一個元素,a 多了一層;b.extend([4, 5]) 則是 4、5 直接接在後面,還是同一層。
remove 和 del 都能拿掉元素,一個看值、一個看位置。remove(x) 拿掉第一個等於 x 的元素;del 則直接刪掉指定位置的那個:
nums = [10, 20, 30, 20, 40]
nums.remove(20)print(nums)
del nums[1]print(nums)加總、最大、最小
Section titled “加總、最大、最小”對一個數字串列,sum()、max()、min() 分別算出總和、最大值、最小值。配合 len() 就能算平均:
scores = [85, 92, 78, 90, 88]
print(sum(scores))print(max(scores))print(min(scores))print(sum(scores) / len(scores))前面用過 sort() 直接把原串列排好。如果不想動到原串列,改用 sorted(),它會回傳一個排好的新串列,原本的不變。兩者都可以加 reverse=True 改成由大到小:
nums = [3, 1, 4, 1, 5, 9, 2]
print(sorted(nums))print(sorted(nums, reverse=True))print(nums)
nums.sort()print(nums)sort() 和 sorted() 還能用 key 指定「依什麼排序」。下面依字串長度排,而不是預設的字母順序:
words = ["banana", "kiwi", "apple", "fig"]
print(sorted(words, key=len))要從一個範圍或另一個串列快速做出新串列,可以用串列生成式:把「要放進去的東西」和「一個 for」寫在同一組中括號裡。後面還能接 if 只留下符合條件的:
squares = [n * n for n in range(1, 6)]print(squares)
evens = [n for n in range(1, 11) if n % 2 == 0]print(evens)第一個做出 1 到 5 的平方;第二個只留下 1 到 10 裡的偶數。
其實生成式就是把一般迴圈壓成一行。上面第一個 [n * n for n in range(1, 6)],等於下面這段你已經熟悉的寫法:
squares = []for n in range(1, 6): squares.append(n * n)看不太習慣時,就把生成式在心裡還原成這種 for + append 的樣子。生成式寫熟了很好用,但別為了短而硬把複雜邏輯塞進一行,那樣還是拆成一般迴圈比較好讀。
從輸入建立串列
Section titled “從輸入建立串列”很多題目會一次輸入一整排數字。split() 把輸入的一行依空白切成一串字串,再用 map(int, ...) 把每個都轉成整數,最後用 list() 收成串列:
line = input("輸入幾個數字,用空白隔開:")nums = list(map(int, line.split()))
print(nums)print(sum(nums))list(map(int, line.split())) 是很常見的固定寫法,看到就知道是「把一行數字讀成整數串列」。
別名:兩個名字,同一個串列
Section titled “別名:兩個名字,同一個串列”這一段很重要,也是很多人踩過的坑。把一個串列指定給另一個名字,並不會複製,兩個名字會指向同一個串列:
a = [1, 2, 3]b = a
b.append(4)
print("a =", a)print("b =", b)注意看右邊的物件面板:a 和 b 的箭頭指向同一個串列。所以透過 b 加東西,從 a 看也變了。它們本來就是同一份。
用 .copy() 複製一份
Section titled “用 .copy() 複製一份”真的想要一份獨立的複本,要用 .copy()。這樣 a 和 b 會指向兩個不同的串列,改一個不影響另一個:
a = [1, 2, 3]b = a.copy()
b.append(4)
print("a =", a)print("b =", b)物件面板這次會出現兩個串列,a、b 各指一個。
巢狀串列與淺複製的陷阱
Section titled “巢狀串列與淺複製的陷阱”.copy() 只複製「最外層」。如果串列裡面還裝著串列,裡層的那些還是共用的。下面 b 是 a 的複本,但改動 b 裡面的小串列,a 竟然也跟著變:
a = [[1, 2], [3, 4]]b = a.copy()
b[0].append(99)
print("a =", a)print("b =", b)從物件面板看得很清楚:外層是兩個不同的串列沒錯,但它們裡面的小串列是同一個。這種只複製一層的叫淺複製。
要連裡面每一層都複製一份,得用 copy 模組的 deepcopy(深複製):
import copy
a = [[1, 2], [3, 4]]b = copy.deepcopy(a)
b[0].append(99)
print("a =", a)print("b =", b)這次改 b,a 完全不受影響,因為連裡層都各自獨立了。
串列裡裝串列,就能表示像表格、棋盤那樣的二維資料。用兩個索引取值:第一個選第幾列,第二個選那一列裡的第幾個:
grid = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(grid[0])print(grid[1][2])搭配兩層迴圈,就能走過每一格:
grid = [[1, 2, 3], [4, 5, 6]]
for row in grid: for value in row: print(value)