列表概念重溫與基礎小測
本部分先重溫 Python 中「列表(list)」的基本概念,提供可執行的示範程式,最後有 3 題小測題目。 小測題目會由題庫中隨機抽出,並可以按「下一題」換另一條題目。
什麼是列表(list)?
在 Python 中,列表(list) 是一種可以按照順序儲存多個值的資料結構,例如一班同學的分數、名字等。
- 用 [ ](方括號)包住整個列表。
- 元素之間用逗號分隔,例如 [60, 75, 88]。
- 可以儲存不同類型的資料(整數、字串……),甚至可以混合。
- 列表中的順序有意義,可以透過「索引」(index)按位置讀取或修改元素。
例如:
一些常用操作
- 讀取元素:scores[0](第一個元素,索引從 0 開始)。
- 修改元素:scores[1] = 90(把第二個元素改為 90)。
- 長度(元素個數):len(scores)。
- 在尾部加入新元素:scores.append(100)。
重點摘要:以下內容補充列表的核心概念,並整理本單元最常用的 4 個常用的程式(加總、點算、檢索、找最大值)。
- 掌握
索引從 0 開始、len()與append()的用途。 - 理解何時必須用
for i in range(len(list))(需要索引才能更新/比較)。 - 避免常見錯誤:越界、少做/多做一格(off-by-one)、忘記初始化變量。
列表(list)是一種有序(order)的資料結構,用來把多個資料放在同一個變量內。列表的順序有意義,因此我們可以用「位置」去存取資料。
- 有序:第一個、第二個……的次序固定,輸出時亦會依原次序顯示。
- 可變(mutable):列表的元素可以被修改,例如
scores[1] = 90。 - 常見用途:存放分數、姓名、每日溫度、庫存數量等「多筆同類型資料」。
Python 的列表索引由 0 開始:索引 0 代表第一個元素,索引 1 代表第二個元素,如此類推。
- 第一項:
scores[0] - 最後一項:
scores[len(scores)-1]或scores[-1] - 倒數第二項:
scores[-2]
注意:如果索引超出範圍(例如列表只有 3 項卻使用 scores[3]),會出現 IndexError。
len(list) 用於取得列表的元素個數;append(x) 用於把新元素加入到列表尾端。
- 當需要「逐項處理」列表時,
len()常用於配合range()產生索引。 - 當需要「由空列表逐步累積結果」時,常用
append()。
列表走訪有兩種常見寫法:
- 只讀取元素:
for x in list:(適合加總、點算等) - 需要索引 i:
for i in range(len(list)):(適合更新列表、比較相鄰元素、同時處理兩個列表)
當題目要求你使用 marks[i]、或需要改寫 list[i] 的值,就必須使用「索引循環」。
大部分列表題都可以套用以下模板,先「初始化變量」,再在 for 循環內逐項更新。
- 忘記初始化:例如未先把
total = 0就直接累加。 - range 寫錯:一般情況用
range(len(list));比較相鄰元素才用range(len(list)-1)。 - 越界:最後一項索引是
len(list)-1,不是len(list)。 - 輸出不合格式:自動批改通常只檢查指定輸出;題目要求輸出甚麼就只輸出甚麼。
列表示範程式(由題庫載入,可修改後按「Run 程式」)
示範程式已放在 ../data/dch5/list-demos.json,本頁會自動載入並生成編輯器。
列表基礎概念小測
完成以下 3 題。每題會由題庫中隨機抽出題目,答完如想再練習,可以按「下一題」換另一條。
5.1 列表基本練習
以下練習會利用 Python 編譯器及自動批改,重點練習 for i in range(...) 和列表操作。 每題下方均提供輸入/輸出示例。
重點摘要:以下 9 題屬於「示範」練習。建議你先記熟每題對應的例子,再對照題目要求的變量名稱與輸出格式。
- 加總 / 平均:先累加
total,再視乎需要計算average。 - 點算 / 檢索 / 最大值:在循環內用
if更新變量。 - 調項(插入 / 刪除):重點在「由尾向前搬」或「由前向後搬」,避免覆蓋資料。
本題要求你不用 sum(),而是使用索引循環逐項把分數加到 total。
- 先初始化:
total = 0 - 用
for i in range(len(marks))逐個索引讀取marks[i] - 每次累加:
total = total + marks[i] - 最後只輸出
total
檢查:是否「只輸出 total」?有沒有多餘文字或多行輸出?
平均分的核心是:平均 = 總和 ÷ 個數。個數就是 len(marks)。
- 先用循環把總和算到
total - 循環後計算:
average = total / len(marks) - 輸出
average(通常會是小數)
若 marks 內含浮點數(例如 56.0),average 亦會自然變成浮點數。
線性檢索(Linear Search)是指由頭到尾逐項比較,直到找到目標值 target 或走完整個列表。
- 先設
found = False - 循環內比較:若
marks[i] == target,則把found改為 True - 循環後按 found 輸出
Found或Not found
加入 break 可提升效率(找到就停止),但不是必須。
「點算」類題目通常只需要一個計數器:遇到符合條件就加 1。
請留意條件是 >= 50(包含 50)。
找最大值時,不能把 highest 初始化為 0(因為分數可能有負數或列表可能不是分數)。最穩妥的方法是:
- 先令
highest = marks[0](假設第一項是最大) - 逐項比較,若更大就更新
若列表已由小至大排序,必定滿足:每一項都不大於下一項,即 numbers[i] <= numbers[i+1]。
- 先設
is_sorted = True - 只需要做到倒數第二項,所以循環用
range(len(numbers)-1) - 一旦發現
numbers[i] > numbers[i+1],就設為 False(可選:break)
插入的核心概念是:先把列表「加長一格」騰出空位,然後由尾部開始逐項向右搬,最後把新元素放到 pos。
- 先
append一個佔位元素(例如空字串) - 用倒序循環:
for i in range(len(names)-1, pos, -1) - 搬位:
names[i] = names[i-1] - 最後:
names[pos] = new_name
為甚麼要「由尾向前」?因為如果由前向後搬,會提早覆蓋未搬走的原有資料。
刪除某一項後,後面的元素需要向前補位,最後列表會多出一個「重複的尾項」,因此要刪除最後一格。
- 由
pos開始到倒數第二項:for i in range(pos, len(names)-1) - 向前搬:
names[i] = names[i+1] - 刪除最後一項:
del names[-1]
本節所講的調動列表項目,並非把兩個元素直接對調(交換),
而是先把目標元素暫存,再使用 for 循環把中間的元素
逐一向前或向後移動,騰出位置後,才把該元素放入指定索引。
這種做法能清楚展示陣列在「插入」操作時,其餘元素如何因為位移 而改變位置,亦是 DSE 常見的陣列處理思維。
重點提醒:
陣列本身並沒有真正的「插入」指令;
所謂插入,其實是先搬移其他元素,
再把資料放入騰出來的位置。
題目要求輸出 print(positions),請確保最後確實有輸出。
5.2 字串:從子串中提取所需字符
本部分主要練習利用索引或切片,從一條字串中抽取需要的部分,例如從電郵地址抽出用戶名稱。 同樣提供 Python 編輯器及自動批改功能。
重點摘要:本部分重點是「索引」與「切片(slice)」。
- 切片語法:
s[start:end](end 不包含)。 - 負索引:
-1代表最後一個字元,s[-4:]可取最後 4 個字元。 - 遇到分隔符(例如
@、-)時,先找位置再切片。
題目要取出開頭三個字元,因此直接使用切片即可:
code[0:3]會取索引 0、1、2(共 3 個字元)。- 切片的 end(右邊界)不包含在結果內,因此 3 代表「取到索引 2 為止」。
電郵地址的結構通常是 username@domain。要取 domain(@ 後面),做法如下:
- 用
for i in range(len(email))逐個字元檢查。 - 當
email[i] == '@',記下at_pos = i。 - 用
email[at_pos + 1:]取出 @ 後面全部字元。
本題通常不建議使用 split()(題目已明確要求)。
不論電話號碼有沒有 -,最後 4 個字元都可用 phone[-4:] 取得。
切片會保留前導 0(例如 0000 不會變成 0)。
若學生編號格式固定為 SYYYY-xxxx,年份永遠在索引 1 至 4,因此可直接切片:
如果將來格式不固定,可改用循環先找出 - 的位置,再用切片抽出年份。
5.3 綜合解難:10 條 Python 題
以下 10 題會綜合運用:加總、平均、比較、計數、線性檢索、更新列表、字串處理 等技巧。
部分題目會要求使用指定變量名稱(例如 pass_count、highest),
系統的隱藏測試個案會讀取這些變量來評分。
⚠️ 題目指明的變量名稱請照樣使用,否則系統將無法讀取,並當作答錯處理。
每題下方都有「輸入與輸出示例」,以及一個「顯示提示」按鈕,協助學生按步驟完成解題。
重點摘要:綜合題最重要的是:先弄清楚「要更新的變量」與「要輸出的結果」,再把它們放入正確的循環模板。
- 同一個
for循環可以同時做多件事(例如:加總 + 點算 + 找最大)。 - 需要「首次達成」或「找到就停」時,使用旗標(flag)或
break。 - 涉及兩個列表時,通常用
for i in range(len(list))同步處理listA[i]與listB[i]。
本題要在同一個列表 marks 上,同時計算「總分、平均、合格人數、最高分」。最有效的方法是:用同一個循環逐項讀取分數,並同步更新多個變量。
- 初始化:
total = 0、pass_count = 0、highest = marks[0]。 - 循環內:把目前分數加到 total;若分數
>= 50就 pass_count +1;若分數更高就更新 highest。 - 循環後:
average = total / len(marks)(平均要在循環後計算)。
系統會讀取 pass_count、average、highest;變量名稱必須完全相同。
重點是維持兩個變量:max1(最高)與 max2(第二高)。當找到新最高分時,舊最高分要先「降級」到第二高。
- 初始化:
max1 = marks[0]、max2 = marks[0]。 - 若
m > max1:先令max2 = max1,再令max1 = m。 - 否則若
m介乎max2與max1:更新max2 = m。
本題屬於「點算」:統計有多少天溫度 >= 35。只要計數器大於 0,就輸出 Heat alert。
本題是「分類點算」:每個年齡不是成人票就是小童票,因此用 if...else 分別累計。
條件是 >= 12,表示 12 歲也算成人票。
本題要找「首次」達標的日子,因此除了累積總和 total,還要確保只記錄第一次達標。
- 初始化:
reach_day = -1、total = 0。 - 逐日累加:
total = total + savings[i]。 - 若
total >= target且reach_day == -1,則把reach_day = i + 1(第幾天以 1 開始)。
本題要檢查密碼是否含有至少一個數字字元。做法是逐個字元檢查,找到數字就把 has_digit 設為 True。
字元比較可以寫成 '0' <= ch <= '9'(Python 允許連鎖比較)。
電郵地址格式為 username@domain。題目要求取 @ 前面的部分。
- 用 for 循環找出
@的索引。 - 用切片:
username = email[0:i]。 - 找到後可
break,避免繼續循環。
本題同時有兩個列表:stock 與 sold。位置 i 代表同一本書,因此要用同一個索引 i 同步處理。
題目禁止直接用 classA + classB,因此要建立空列表,再用兩個循環分別加入。
完成後可用 len(all_marks) 檢查總人數是否正確。
本題要建立新列表 grades,把每個分數轉成 'A'、'B' 或 'F'。做法是逐項判斷並 append 對應等級。