1. 前言
Python 的「列表生成式(List Comprehension)」是一種用來簡潔建立列表的便利語法。相較於使用一般的 for
迴圈來建立列表,這種寫法在程式碼可讀性與執行效率上都有明顯優勢。
特別是當列表生成式搭配 if
條件語句時,可以只篩選出符合條件的元素,讓列表操作更具彈性。本文將從基礎到進階,搭配實用範例,詳盡介紹如何在 Python 中結合列表生成式與 if
條件語句。
什麼是列表生成式?
列表生成式是一種能讓你簡潔撰寫 Python 列表的語法。相比傳統的 for
迴圈,它可以讓你用更少的程式碼撰寫出更易讀的邏輯。
例如,如果你想建立一個從 0 到 4 的整數列表,使用傳統的 for
迴圈寫法如下:
2. Python 列表生成式的基礎
在前一節中,我們介紹了什麼是列表生成式以及它的優點。本節將進一步說明列表生成式的基本語法,並透過具體範例幫助你更深入理解。
列表生成式的基本語法
列表生成式的基本語法如下:
[運算式 for 變數 in 可疊代物件]
語法組成說明
運算式
:針對變數進行的處理(例如計算或函數)for 變數 in 可疊代物件
:從可疊代物件(如列表、元組、range 等)中逐一取出元素的迴圈
例如,要建立一個包含從 0 到 4 整數的列表,使用傳統 for
迴圈會像這樣:
numbers = []
for i in range(5):
numbers.append(i)
print(numbers) # [0, 1, 2, 3, 4]
但使用列表生成式時,只需要一行就能完成:
numbers = [i for i in range(5)]
print(numbers) # [0, 1, 2, 3, 4]
列表生成式的基本範例
透過列表生成式,我們可以更簡潔地進行列表建立與轉換。以下是幾個常見的基本應用:
1. 將每個元素平方
以下是將 0 到 9 的整數平方後存入列表的範例:
squares = [i**2 for i in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
使用傳統 for
迴圈的寫法如下:
squares = []
for i in range(10):
squares.append(i**2)
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
2. 轉換字串列表
將字串列表中的所有字串轉為大寫:
words = ["python", "list", "comprehension"]
uppercase_words = [word.upper() for word in words]
print(uppercase_words) # ['PYTHON', 'LIST', 'COMPREHENSION']
傳統寫法如下:
words = ["python", "list", "comprehension"]
uppercase_words = []
for word in words:
uppercase_words.append(word.upper())
print(uppercase_words) # ['PYTHON', 'LIST', 'COMPREHENSION']
3. 扁平化列表(將巢狀列表展開)
當我們想將二維列表轉為一維列表時,也可以使用列表生成式:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
使用傳統寫法則如下:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = []
for row in matrix:
for num in row:
flattened.append(num)
print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
透過列表生成式,即使是巢狀迴圈也能用簡潔的一行來實現。
3. 搭配 if
條件的列表生成式
在上一節中,我們學習了列表生成式的基本用法。從這裡開始,我們將說明如何將 if
條件語句結合到列表生成式中,建立具條件篩選的列表。
透過在列表生成式中加入 if
,可以輕鬆過濾出符合特定條件的元素,讓列表建立更具彈性與效率。
if
條件的列表生成式基本語法
若想根據條件建立列表,基本語法如下:
[運算式 for 變數 in 可疊代物件 if 條件]
語法說明
運算式
:對每個元素所執行的操作for 變數 in 可疊代物件
:對可疊代物件(如列表、元組、range 等)進行的迴圈if 條件
:僅當條件為真時,該元素才會加入列表
基本使用範例
1. 篩選偶數
例如,我們要從 0 到 9 的整數中,挑出偶數並加入列表:
evens = []
for i in range(10):
if i % 2 == 0:
evens.append(i)
print(evens) # [0, 2, 4, 6, 8]
使用列表生成式則更簡潔:
evens = [i for i in range(10) if i % 2 == 0]
print(evens) # [0, 2, 4, 6, 8]
→ 將 if
寫入列表生成式中,可以省略 append()
,讓程式碼更短更易讀。
2. 過濾字串列表
你也可以使用列表生成式,從字串列表中篩選符合條件的元素:
例如,從 ["python", "java", "c++", "ruby"]
中,選出字數 5 個以上的程式語言:
languages = ["python", "java", "c++", "ruby"]
long_languages = [lang for lang in languages if len(lang) >= 5]
print(long_languages) # ['python']
3. 抽取包含特定字元的單字
若要從列表中篩選包含某特定字母的單字,也可以用列表生成式來達成。
以下是範例,抽取包含 "a"
的單字:
words = ["apple", "banana", "cherry", "date"]
words_with_a = [word for word in words if "a" in word]
print(words_with_a) # ['apple', 'banana', 'date']
如何指定多個條件
在 if
條件中,你可以使用 and
或 or
來組合多個條件。
1. 抽出同時為偶數且為 3 的倍數的數字
filtered_numbers = [i for i in range(20) if i % 2 == 0 and i % 3 == 0]
print(filtered_numbers) # [0, 6, 12, 18]
2. 過濾同時符合多條件的字串
words = ["python", "java", "c++", "ruby", "go", "haskell"]
filtered_words = [word for word in words if len(word) >= 5 and "o" in word]
print(filtered_words) # ['python']
常見錯誤與解法
1. if
的位置錯誤
❌ 錯誤示範(if
放在錯誤的位置)
numbers = [if i % 2 == 0 for i in range(10)]
錯誤訊息:SyntaxError: invalid syntax
✔ 正確寫法
numbers = [i for i in range(10) if i % 2 == 0]
2. 錯誤使用 and
/ or
❌ 錯誤示範
words = ["apple", "banana", "cherry"]
filtered_words = [word for word in words if len(word) > 5 or "a" in word]
✔ 若想同時滿足多個條件,請使用 and
filtered_words = [word for word in words if len(word) > 5 and "a" in word]
小結
- 在列表生成式中加入
if
,可以根據條件篩選元素 - 語法為:
[運算式 for 變數 in 可疊代物件 if 條件]
- 可用於篩選偶數、字串過濾等各種場景
- 支援
and
/or
多條件組合 - 注意
if
的位置與條件語法,避免語法錯誤
4. 使用 if-else
的列表生成式
在上一節中,我們學會了如何使用 if
來篩選符合條件的元素。不過,如果你想根據條件來決定不同的值加入列表,就需要搭配 if-else
一起使用。
本節將說明如何撰寫含有 if-else
的列表生成式,並提供實用範例幫助你理解其應用。
if-else
列表生成式的基本語法
若要在列表生成式中加入 if-else
條件,其語法如下:
[值1 if 條件 else 值2 for 變數 in 可疊代物件]
語法說明
值1
:當條件成立時,要加入列表的值條件
:if
所判斷的條件else 值2
:當條件不成立時,要加入的值for 變數 in 可疊代物件
:遍歷可疊代物件的迴圈
⚠ 注意:當使用 if-else
時,if
要寫在 for
的前面!
→ 如果只用 if
,它會寫在 for
的後面;但 if-else
時,必須寫在前面。
基本範例
1. 偶數保持原樣,奇數改為 “odd”
以下範例將 0 到 9 的整數中,偶數保持原值,奇數改成字串 “odd”:
numbers = []
for i in range(10):
if i % 2 == 0:
numbers.append(i)
else:
numbers.append("odd")
print(numbers)
# [0, 'odd', 2, 'odd', 4, 'odd', 6, 'odd', 8, 'odd']
使用列表生成式則只需一行:
numbers = [i if i % 2 == 0 else "odd" for i in range(10)]
print(numbers)
# [0, 'odd', 2, 'odd', 4, 'odd', 6, 'odd', 8, 'odd']
→ 透過 if-else
,你可以根據條件靈活地轉換每個元素的值。
2. 將小於等於 0 的數值轉為 “negative”
假設我們有一個包含正負數值的列表,要將小於等於 0 的值替換為 “negative”:
numbers = [-5, 3, 0, 8, -2, 7]
modified_numbers = [num if num > 0 else "negative" for num in numbers]
print(modified_numbers)
# ['negative', 3, 'negative', 8, 'negative', 7]
3. 根據正負數進行分類
將數值分類為 “positive” 或 “negative” 的例子如下:
numbers = [-10, 15, 0, -5, 20]
categories = ["positive" if num > 0 else "negative" for num in numbers]
print(categories)
# ['negative', 'positive', 'negative', 'negative', 'positive']
使用 if-else
時的注意事項
1. if
的位置要正確
❌ 錯誤寫法(會出現語法錯誤)
numbers = [i for i in range(10) if i % 2 == 0 else "odd"]
錯誤訊息:SyntaxError: invalid syntax
✔ 正確寫法
numbers = [i if i % 2 == 0 else "odd" for i in range(10)]
👉 要記得:if-else
要放在 for
前面!
2. if
和 if-else
的差異
- 只用
if
:用來過濾元素
evens = [i for i in range(10) if i % 2 == 0]
print(evens) # [0, 2, 4, 6, 8]
→ 條件不符合的元素會被排除。
- 使用
if-else
:根據條件轉換每個值
numbers = [i if i % 2 == 0 else "odd" for i in range(10)]
print(numbers)
# [0, 'odd', 2, 'odd', 4, 'odd', 6, 'odd', 8, 'odd']
→ 所有元素都會加入列表,只是依據條件決定值的內容。
小結
- 使用
if-else
可以根據條件決定不同的值加入列表 if-else
必須寫在for
的前面- 與只用
if
的列表生成式不同,if-else
不會排除任何元素 - 適合用於數值分類、字串替換等場合
- 也可以使用巢狀
if-else
來應對多條件判斷
5. 巢狀列表生成式與條件判斷
在上一節中,我們學習了如何使用 if-else
進行條件處理。本節將介紹如何使用 巢狀列表生成式(多重迴圈的列表生成式)。
列表生成式就像傳統 for
迴圈一樣,也可以使用 巢狀迴圈。這讓我們可以更有效率地處理二維列表(例如列表中的列表)。
巢狀列表生成式的基本語法
要在列表生成式中使用多重迴圈,其基本語法如下:
[運算式 for 變數1 in 可疊代物件1 for 變數2 in 可疊代物件2]
語法說明
運算式
:針對變數進行的操作for 變數1 in 可疊代物件1
:外層迴圈for 變數2 in 可疊代物件2
:內層迴圈
重點是:執行順序是從左到右,和一般的巢狀迴圈邏輯一致。
基本範例
1. 將二維列表「扁平化」
假設我們有一個二維列表,想將其轉換為一維列表,可以這樣做:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = []
for row in matrix:
for num in row:
flattened.append(num)
print(flattened)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
使用列表生成式就能一行完成:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
→ 巢狀列表生成式能讓你用更簡潔的方式處理巢狀結構的資料。
2. 建立所有組合
例如,我們想將 A, B, C
和 1, 2, 3
組成所有可能的組合:
letters = ["A", "B", "C"]
numbers = [1, 2, 3]
combinations = []
for letter in letters:
for number in numbers:
combinations.append(f"{letter}{number}")
print(combinations)
# ['A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3']
使用列表生成式的寫法如下:
letters = ["A", "B", "C"]
numbers = [1, 2, 3]
combinations = [f"{letter}{number}" for letter in letters for number in numbers]
print(combinations)
# ['A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3']
→ 使用巢狀列表生成式可以將多重迴圈壓縮成簡潔的一行。
結合條件判斷
在巢狀列表生成式中,也可以搭配 if
或 if-else
來進行條件篩選或值的轉換。
3. 篩選總和為偶數的數字對
從 1~3
與 4~6
中,找出「總和為偶數」的數字對:
list1 = [1, 2, 3]
list2 = [4, 5, 6]
pairs = []
for x in list1:
for y in list2:
if (x + y) % 2 == 0:
pairs.append((x, y))
print(pairs)
# [(1, 5), (2, 4), (2, 6), (3, 5)]
使用巢狀列表生成式可以寫得更簡潔:
list1 = [1, 2, 3]
list2 = [4, 5, 6]
pairs = [(x, y) for x in list1 for y in list2 if (x + y) % 2 == 0]
print(pairs)
# [(1, 5), (2, 4), (2, 6), (3, 5)]
使用巢狀列表生成式的注意事項
✅ 1. 可讀性容易下降
- 巢狀太深時可讀性會變差,請避免過度使用
- 若可讀性為首要考量,建議改用傳統
for
迴圈
✅ 2. 注意 if
的位置
只使用 if
時 → 寫在for
的後面使用 if-else
時 → 寫在for
的前面
✅ 3. 巢狀太深時,考慮拆成函數
- 當邏輯變得太複雜時,與其硬寫成一行列表生成式,不如改用函數來提高可讀性
小結
- 巢狀列表生成式可以簡化二維資料的處理與多重迴圈邏輯
- 可以結合
if
條件來篩選符合條件的項目 - 也可以使用
if-else
根據條件設定不同的值 - 但巢狀過深會影響可讀性,請依情況選擇是否使用
6. 列表生成式的最佳實踐與注意事項
列表生成式是 Python 中非常方便的功能,可以讓你用更簡潔的方式撰寫程式碼。但若使用不當,可能會導致可讀性變差或效能下降。
本節將說明 如何正確使用列表生成式的最佳實踐與常見注意事項。
適合使用列表生成式的情境
以下是幾個適合使用列表生成式的情境:
1. 簡單的列表建立
當你只是要進行簡單的元素轉換或建立列表時,使用列表生成式是非常合適的。
範例:將每個元素平方
squares = [x**2 for x in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
2. 條件過濾(篩選元素)
當你需要從列表中篩選出符合特定條件的項目時,列表生成式非常適合。
範例:過濾出偶數
evens = [x for x in range(10) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8]
3. 字串列表轉換
列表生成式在處理字串列表的轉換時也非常實用。
範例:將字串轉成大寫
words = ["python", "list", "comprehension"]
uppercase_words = [word.upper() for word in words]
print(uppercase_words) # ['PYTHON', 'LIST', 'COMPREHENSION']
4. 扁平化巢狀列表
當你需要將二維列表轉換成一維列表 時,列表生成式可以大幅簡化寫法。
範例:將二維列表展平成一維列表
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
不適合使用列表生成式的情況
以下是使用列表生成式時應避免的情況:
1. 巢狀過深,導致可讀性差
列表生成式雖然簡潔,但若巢狀太深,可讀性會明顯下降。
❌ 不佳範例:三層巢狀迴圈
matrix = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
flattened = [num for row in matrix for subrow in row for num in subrow]
👉 太難閱讀,不容易維護
✅ 建議改寫為傳統 for
迴圈:
flattened = []
for row in matrix:
for subrow in row:
for num in subrow:
flattened.append(num)
2. 處理邏輯太長,導致程式碼混亂
列表生成式的優勢在於簡潔的一行式寫法,若條件過於複雜反而會造成混亂。
❌ 不佳範例:條件與運算太多
numbers = [x**2 if x % 2 == 0 else x**3 for x in range(10) if x != 5 and x % 3 != 0]
✅ 建議使用傳統寫法來提升可讀性:
numbers = []
for x in range(10):
if x != 5 and x % 3 != 0:
if x % 2 == 0:
numbers.append(x**2)
else:
numbers.append(x**3)
列表生成式的效能表現
1. 比 for
迴圈更快
列表生成式通常比傳統的 for
迴圈執行得更快,因為 Python 會對其進行內部最佳化。
效能比較範例:
import time
data = list(range(10**6))
# 使用列表生成式
start = time.time()
squares = [x**2 for x in data]
print("列表生成式:", time.time() - start)
# 使用傳統 for 迴圈
start = time.time()
squares = []
for x in data:
squares.append(x**2)
print("傳統 for 迴圈:", time.time() - start)
- 列表生成式通常能快上 30%~50%
- 但會一次性佔用大量記憶體
2. 若需節省記憶體,可使用生成器表達式
當資料量龐大時,建議使用 生成器(generator expression) 來取代列表生成式。
# 列表生成式(耗記憶體)
squares = [x**2 for x in range(10**6)]
# 生成器表達式(省記憶體)
squares_gen = (x**2 for x in range(10**6))
→ squares_gen
不會立即建立整個列表,而是逐一產生值,節省記憶體。
小結
✅ 適合使用列表生成式的情況
- 簡單的列表建立
- 條件過濾
- 字串轉換
- 扁平化二維列表
❌ 不建議使用的情況
- 巢狀太深的處理
- 條件或運算過於複雜
- 影響可讀性的長行程式碼
💡 最佳實踐
- 簡單邏輯請使用列表生成式
- 複雜邏輯請用傳統
for
迴圈 - 根據效能與可讀性選擇正確的寫法
7. 常見問題(FAQ)
在本節中,我們將解答有關 列表生成式的常見疑問,並說明實際開發時應注意的重點。這些問題包含新手常犯錯誤與效能上的疑慮。
Q1. 可以在列表生成式中使用兩次 if
嗎?
A1. 可以,但需注意可讀性。
在列表生成式中,if
可以寫兩次以上,達到多重條件的篩選效果。
範例:篩選同時為偶數且為 3 的倍數的數字
filtered_numbers = [x for x in range(30) if x % 2 == 0 if x % 3 == 0]
print(filtered_numbers) # [0, 6, 12, 18, 24]
這種寫法效果就像「AND 條件」。但從可讀性角度來看,使用 and
會更清楚:
filtered_numbers = [x for x in range(30) if x % 2 == 0 and x % 3 == 0]
Q2. 列表生成式和傳統 for
迴圈,該用哪一個?
A2. 根據邏輯的簡單程度與可讀性選擇最適合的方式。
如果處理邏輯 簡單明確,列表生成式非常實用;但若邏輯 複雜多層,傳統迴圈會比較清楚易懂。
範例:建議用傳統 for
迴圈的情況
# ❌ 難以閱讀的列表生成式
numbers = ["Even" if x % 2 == 0 else "Odd" if x % 3 == 0 else "Other" for x in range(10)]
# ✅ 傳統寫法更清楚
numbers = []
for x in range(10):
if x % 2 == 0:
numbers.append("Even")
elif x % 3 == 0:
numbers.append("Odd")
else:
numbers.append("Other")
Q3. if
和 if-else
的用途有什麼不同?
A3. if
用於篩選,if-else
用於值的轉換。
✅ 僅使用 if
:只留下符合條件的元素
evens = [x for x in range(10) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8]
→ 不符合條件的項目會被排除。
✅ 使用 if-else
:保留所有元素,但根據條件轉換值
labels = ["even" if x % 2 == 0 else "odd" for x in range(10)]
print(labels)
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
Q4. 列表生成式真的比 for
迴圈快嗎?
A4. 一般來說是的,但記憶體使用量會較高。
Python 的列表生成式因為有內部優化,通常會比 for
迴圈快。
⏳ 實測範例:處理 100 萬筆資料
import time
data = list(range(10**6))
# 使用列表生成式
start = time.time()
squares = [x**2 for x in data]
print("列表生成式:", time.time() - start)
# 使用 for 迴圈
start = time.time()
squares = []
for x in data:
squares.append(x**2)
print("for 迴圈:", time.time() - start)
- 列表生成式通常快上 30~50%
- 但會一次載入整個列表,占用較多記憶體
💡 解法:使用生成器(generator expression)
若處理大量資料時想節省記憶體,請改用生成器:
squares_gen = (x**2 for x in data) # 使用 () 創建生成器
Q5. 除了 list
,set
和 dict
也能用內涵式嗎?
A5. 當然可以!Python 也支援 set
和 dict
內涵式。
✅ set
(集合)內涵式範例:
unique_squares = {x**2 for x in range(10)}
print(unique_squares)
✅ dict
(字典)內涵式範例:
squares_dict = {x: x**2 for x in range(10)}
print(squares_dict)
小結
- 可使用兩次
if
,但建議使用and
提高可讀性 if
用於篩選元素,if-else
用於值的轉換- 列表生成式通常比
for
快,但會占用較多記憶體 set
和dict
也支援內涵式語法
以上就是 Python 中有關列表生成式與 if
組合的完整說明!🎉
歡迎你實際動手寫程式,加深理解,真正掌握這項強大的語法技巧!🚀