跳到內容

串列 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 在不在串列裡,回傳 TrueFalse

還有更多常用的方法:

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(另一個串列):把另一個串列的元素全接到後面。

appendextend 很容易搞混,兩個都是往後面加,差在怎麼加。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 直接接在後面,還是同一層。

removedel 都能拿掉元素,一個看值、一個看位置。remove(x) 拿掉第一個等於 x 的元素;del 則直接刪掉指定位置的那個:

nums = [10, 20, 30, 20, 40]
nums.remove(20)
print(nums)
del nums[1]
print(nums)

對一個數字串列,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 的樣子。生成式寫熟了很好用,但別為了短而硬把複雜邏輯塞進一行,那樣還是拆成一般迴圈比較好讀。

很多題目會一次輸入一整排數字。split() 把輸入的一行依空白切成一串字串,再用 map(int, ...) 把每個都轉成整數,最後用 list() 收成串列:

line = input("輸入幾個數字,用空白隔開:")
nums = list(map(int, line.split()))
print(nums)
print(sum(nums))

list(map(int, line.split())) 是很常見的固定寫法,看到就知道是「把一行數字讀成整數串列」。

這一段很重要,也是很多人踩過的坑。把一個串列指定給另一個名字,並不會複製,兩個名字會指向同一個串列:

a = [1, 2, 3]
b = a
b.append(4)
print("a =", a)
print("b =", b)

注意看右邊的物件面板:ab 的箭頭指向同一個串列。所以透過 b 加東西,從 a 看也變了。它們本來就是同一份。

真的想要一份獨立的複本,要用 .copy()。這樣 ab 會指向兩個不同的串列,改一個不影響另一個:

a = [1, 2, 3]
b = a.copy()
b.append(4)
print("a =", a)
print("b =", b)

物件面板這次會出現兩個串列,ab 各指一個。

.copy() 只複製「最外層」。如果串列裡面還裝著串列,裡層的那些還是共用的。下面 ba 的複本,但改動 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)

這次改 ba 完全不受影響,因為連裡層都各自獨立了。

串列裡裝串列,就能表示像表格、棋盤那樣的二維資料。用兩個索引取值:第一個選第幾列,第二個選那一列裡的第幾個:

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)