APCS 必學 Python 程式設計:列表推導式

作者:Howshin Wang
#Python#APCS#列表推導式#list comprehension#for迴圈#程式進階#條件篩選#列表處理#Python 風格#程式技巧
APCS  必學 Python 程式設計:列表推導式

TL;DR 重點摘要

  • 列表推導式(List Comprehension)是 Python 最具代表性的寫法之一,能把 for 迴圈濃縮成一行
  • 比起傳統 for 迴圈寫法,列表推導式更簡潔、執行速度也更快
  • 加上 if 條件後,可以一行完成「篩選 + 轉換」的雙重任務
  • APCS 解題時用列表推導式可以省下大量行數,讓主邏輯更清楚
  • 這是從「Python 初學者」進階到「Python 使用者」的關鍵分水嶺

目錄


什麼是列表推導式

列表推導式的概念用一句話講就是:用一行寫出一個建構新列表的迴圈

它的基本格式長這樣:

[ 表達式 for 變數 in 來源 ]

舉個例子,要建立 1 到 5 的平方列表:

squares = [x * x for x in range(1, 6)]
print(squares)
# 輸出: [1, 4, 9, 16, 25]

讀法:「對於每個從 range(1, 6) 出來的 x,把 x * x 收集成新列表」。


從 for 迴圈到列表推導式

我們來比較同樣的功能用兩種寫法的差別。任務:把 [1, 2, 3, 4, 5] 每個元素都乘以 10。

用 for 迴圈寫:

nums = [1, 2, 3, 4, 5]
result = []
for x in nums:
    result.append(x * 10)
print(result)
# 輸出: [10, 20, 30, 40, 50]

四行程式碼,要先建空列表、寫迴圈、再 append()

用列表推導式寫:

nums = [1, 2, 3, 4, 5]
result = [x * 10 for x in nums]
print(result)
# 輸出: [10, 20, 30, 40, 50]

一行做完。而且當你習慣這個寫法之後,讀起來會比 for 迴圈更直覺——因為它的順序就是「我想要什麼 ← 從哪裡來」。


加上 if 條件:一行做兩件事

列表推導式真正強大的地方,是可以一邊轉換、一邊篩選。格式是:

[ 表達式 for 變數 in 來源 if 條件 ]

例如,要從 1 到 20 中挑出所有偶數:

evens = [x for x in range(1, 21) if x % 2 == 0]
print(evens)
# 輸出: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

或者,要把一串成績裡及格的科目「加 5 分」:

scores = [55, 72, 48, 90, 63, 38]
boosted = [s + 5 for s in scores if s >= 60]
print(boosted)
# 輸出: [77, 95, 68]

這行程式碼同時做了篩選(只取大於等於 60 的)和轉換(每個都加 5)。用 for 迴圈寫至少要 4-5 行。


APCS 實戰:三個常見應用

應用一:讀進整行數字並只取偶數

# 輸入: 3 8 5 12 7 4 9
nums = list(map(int, input().split()))
evens = [x for x in nums if x % 2 == 0]
print(evens)
# 輸出: [8, 12, 4]

應用二:批次計算每筆資料的平方

# 輸入: 1 2 3 4 5
nums = list(map(int, input().split()))
squares = [x * x for x in nums]
print(squares)
# 輸出: [1, 4, 9, 16, 25]

應用三:從字串中取出所有數字字元

text = "abc123def45g"
digits = [c for c in text if c.isdigit()]
print(digits)
# 輸出: ['1', '2', '3', '4', '5']

isdigit() 是字串方法,會檢查這個字元是不是數字。這在處理「混合文字和數字」的測資時非常實用。


列表推導式 vs map():什麼時候用哪個?

第二篇我們學了 map(),它跟列表推導式很像,但各有適合的場合:

# 簡單套用一個函式 → map() 比較簡潔
nums = list(map(int, input().split()))

# 需要表達式或條件 → 列表推導式比較直覺
squares = [x * x for x in nums]
evens = [x for x in nums if x % 2 == 0]

判斷原則:

  • 只是「轉換型態」或「套用單一函式」→ 用 map()
  • 需要「做運算」或「加條件」→ 用列表推導式

實際上很多 APCS 高手兩種都用,看哪個寫法在當下最清楚就用哪個。


使用時容易出錯的地方

問題一:條件位置寫錯

if 條件在後面是「篩選」,如果想做「條件式轉換」要用 if-else 並放在前面:

# 篩選:只保留偶數
[x for x in range(10) if x % 2 == 0]
# 結果: [0, 2, 4, 6, 8]

# 轉換:偶數保留,奇數變 -1
[x if x % 2 == 0 else -1 for x in range(10)]
# 結果: [0, -1, 2, -1, 4, -1, 6, -1, 8, -1]

兩種 if 的位置和語意完全不同,要分清楚。

問題二:寫得太複雜反而難讀

列表推導式的優點是簡潔,但如果塞太多邏輯進去,反而會比 for 迴圈難讀:

# 太複雜,不建議這樣寫
result = [x * 2 if x > 0 else -x for x in nums if x != 0 and x % 3 == 0]

判斷原則:如果一行寫不下要折行才看得懂,就改回 for 迴圈。程式碼是寫給人讀的,不是越短越好。

問題三:忘了用 [] 包起來

# 錯誤:這是「生成器表達式」,不是列表
result = (x * 2 for x in nums)

# 正確:列表推導式要用方括號
result = [x * 2 for x in nums]

圓括號 () 會產生「生成器(generator)」,雖然 Python 也接受,但跟列表用法不同,初學階段先用 [] 就好。


列表推導式是 Python 寫法現代化的代表。當你開始自然地寫出 [x * 2 for x in nums] 這類程式碼,你已經跟「死記語法」的階段告別,進入「用 Python 風格思考」的世界了。

下一篇開始我們會進入 APCS 解題的核心 —— 二維列表與棋盤地圖,讓你學會處理矩陣、迷宮、棋盤這類常見的考題類型。


AI導師 Python 程式教學 - 隨時可以學習

免費試用

Ah Ha Coding AI 程式教學

?常見問題 FAQ

Q.列表推導式跟 for 迴圈的差別在哪?

兩者結果一樣,但列表推導式可以把多行 for 迴圈壓縮成一行,而且執行速度通常更快。比較看看「把列表每個元素乘以 10」:

# for 迴圈:4 行
result = []
for x in nums:
    result.append(x * 10)

# 列表推導式:1 行
result = [x * 10 for x in nums]

當你習慣這個寫法之後,讀起來其實比 for 迴圈更直覺,因為它的順序就是「我想要什麼 ← 從哪裡來」。

Q.列表推導式怎麼加 if 條件?

if 條件放在 for 後面就是「篩選」:

# 從 1 到 20 中只取偶數
evens = [x for x in range(1, 21) if x % 2 == 0]

也可以同時做篩選和轉換:

# 只取及格分數,並各加 5 分
scores = [55, 72, 48, 90, 63, 38]
boosted = [s + 5 for s in scores if s >= 60]
# 結果: [77, 95, 68]

Q.「篩選」的 if 和「條件式轉換」的 if-else 有什麼不同?

兩者位置和語意都不一樣:

# 篩選:if 在後面,只保留符合條件的
[x for x in range(10) if x % 2 == 0]
# 結果: [0, 2, 4, 6, 8]

# 條件式轉換:if-else 在前面,全部都要、但用條件決定值
[x if x % 2 == 0 else -1 for x in range(10)]
# 結果: [0, -1, 2, -1, 4, -1, 6, -1, 8, -1]

簡單記:只有 if → 在後面(篩選)有 if-else → 在前面(轉換)

Q.列表推導式可以跟 map() 互相取代嗎?什麼時候用哪個?

大部分情況可以互相取代,但各有適合的場景:

  • 只是套用一個現成函式(像 intfloatabs)→ 用 map() 比較簡潔
  • 需要做運算或加條件(像 x*xif x > 0)→ 用列表推導式比較直覺
# map() 適合
nums = list(map(int, input().split()))

# 列表推導式適合
squares = [x * x for x in nums]
evens = [x for x in nums if x % 2 == 0]

很多 APCS 高手兩種都用,看哪個寫法在當下最清楚就用哪個。

Q.列表推導式可以巢狀嗎?例如用在二維列表?

可以。常見的應用是建立二維列表:

# 建立一個 3×4 全部填 0 的二維列表
grid = [[0] * 4 for _ in range(3)]

或是把二維列表「攤平」成一維:

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [x for row in matrix for x in row]
# 結果: [1, 2, 3, 4, 5, 6, 7, 8, 9]

不過巢狀寫法很容易變得難讀,如果一行寫不下就改回 for 迴圈,不要為了短而犧牲可讀性。

Q.為什麼 (x * 2 for x in nums) 不能當成列表用?

因為圓括號 () 產生的是「生成器(generator)」,不是列表。生成器只能走訪一次,而且不能像列表那樣用 len()、索引存取。

# 列表(可重複使用)
result = [x * 2 for x in nums]

# 生成器(只能跑一次,省記憶體)
result = (x * 2 for x in nums)

初學階段一律用方括號 [] 就好,等熟悉後再學生成器在處理大量資料時的優勢。

Q.列表推導式什麼時候反而不該用?

當邏輯太複雜、一行塞不下時,就該改回 for 迴圈。例如:

# 太複雜,難讀
result = [x * 2 if x > 0 else -x for x in nums if x != 0 and x % 3 == 0]

這種情況不如用幾行 for 迴圈寫清楚,程式碼是寫給人讀的,不是越短越好。判斷標準:如果同事或自己過幾天回來看,還能一眼看懂,就保留;看不懂就拆開。