A3: 月球感測器陣列:數據容器與列表操作
任務背景
月球基地配備了數百個感測器,監測溫度、輻射、氣壓等各種數據。作為數據分析員,你需要處理這些大量的感測器讀數。單一變數已經不夠用了,你需要學會使用「數據容器」來管理成批的資訊。
在這個訓練模組中,你將學習:- 如何使用列表(List)儲存多個數據
- 如何遍歷和操作列表中的元素
- 如何使用內建函數進行數據分析
- 列表操作的效能考量
知識點說明
什麼是列表(List)?
列表是 Python 中最常用的數據容器,可以儲存多個相關的資料項。想像它是一排編號的儲物櫃,每個櫃子都可以放入一個數據。
# 創建列表
temperatures = [15, 18, 20, 17, 19]
零基索引(Zero-based Indexing)
⚠️ 重要概念:在程式設計中,索引從 0 開始!
sensors = [100, 200, 300, 400]
# ↑ ↑ ↑ ↑
# 0 1 2 3
print(sensors[0]) # 100 (第一個元素)
print(sensors[3]) # 400 (第四個元素)
列表的創建方式
# 方法 1:直接賦值
data = [1, 2, 3, 4, 5]
# 方法 2:創建 N 個相同值
zeros = [0] * 10 # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# 方法 3:列表生成式(List Comprehension)
squares = [i**2 for i in range(5)] # [0, 1, 4, 9, 16]
列表的基本操作
| 操作 | 語法 | 說明 |
|------|------|------|
| 存取 | lst[i] | 讀取索引 i 的元素 |
| 修改 | lst[i] = value | 修改索引 i 的元素 |
| 長度 | len(lst) | 獲取列表長度 |
| 添加 | lst.append(x) | 在尾部添加元素 |
| 移除 | lst.pop() | 移除並返回最後一個元素 |
遍歷列表的兩種方式
data = [10, 20, 30, 40]
# 方式 1:基於索引(需要索引時使用)
for i in range(len(data)):
print(f"索引 {i}:{data[i]}")
# 方式 2:基於值(語法更簡潔)
for value in data:
print(value)
範例程式碼
範例 1:溫度感測器數據分析
import sys
# 任務:分析一天中各時段的溫度數據
n = int(sys.stdin.readline()) # 感測器數量
temperatures = list(map(int, sys.stdin.readline().strip().split()))
# 基本統計
total = sum(temperatures)
average = total / n
minimum = min(temperatures)
maximum = max(temperatures)
print(f"感測器數量:{n}")
print(f"平均溫度:{average:.1f}°C")
print(f"最低溫度:{minimum}°C")
print(f"最高溫度:{maximum}°C")
print(f"溫差:{maximum - minimum}°C")
範例 2:輻射警報系統
import sys
# 任務:檢查哪些區域的輻射值超過安全標準
n = int(sys.stdin.readline())
radiation_levels = list(map(int, sys.stdin.readline().strip().split()))
safe_limit = 50 # 安全標準
print("輻射監測報告:")
danger_zones = []
for i in range(len(radiation_levels)):
level = radiation_levels[i]
zone = i + 1 # 區域編號從 1 開始
if level > safe_limit:
print(f"⚠️ 區域 {zone}:{level} (超標 {level - safe_limit})")
danger_zones.append(zone)
else:
print(f"✅ 區域 {zone}:{level} (安全)")
if danger_zones:
print(f"\n危險區域:{danger_zones}")
else:
print("\n所有區域安全!")
範例 3:能量收集優化
import sys
# 任務:找出連續 3 個太陽能板中能量收集最多的組合
n = int(sys.stdin.readline())
energy = list(map(int, sys.stdin.readline().strip().split()))
max_energy = 0
best_start = 0
# 滑動窗口:檢查每個連續 3 個板子的組合
for i in range(n - 2): # 注意:要留出空間給後面 2 個元素
window_sum = energy[i] + energy[i+1] + energy[i+2]
if window_sum > max_energy:
max_energy = window_sum
best_start = i
print(f"最佳位置:板子 {best_start+1} 到 {best_start+3}")
print(f"總能量:{max_energy} 單位")
print(f"板子編號:{energy[best_start]}, {energy[best_start+1]}, {energy[best_start+2]}")
範例 4:數據過濾與轉換
import sys
# 任務:過濾掉異常讀數(負值),並將其他讀數轉換為攝氏度
n = int(sys.stdin.readline())
kelvin_readings = list(map(int, sys.stdin.readline().strip().split()))
# 過濾並轉換
celsius_readings = []
for k in kelvin_readings:
if k >= 0: # 只處理有效讀數
c = k - 273 # 開氏溫度轉攝氏溫度
celsius_readings.append(c)
print(f"有效讀數:{len(celsius_readings)}/{n}")
print(f"攝氏溫度:{celsius_readings}")
範例 5:列表生成式的威力
import sys
# 任務:快速生成平方數列表
n = int(sys.stdin.readline())
# 傳統方法
squares_old = []
for i in range(1, n+1):
squares_old.append(i ** 2)
# 列表生成式(更簡潔)
squares_new = [i**2 for i in range(1, n+1)]
print(f"1 到 {n} 的平方數:")
print(squares_new)
# 條件過濾:只要偶數的平方
even_squares = [i**2 for i in range(1, n+1) if i % 2 == 0]
print(f"偶數的平方:{even_squares}")
程式碼解說
關鍵技術點
- 內建函數的效能優勢
# 慢速方法(手動計算)
total = 0
for x in data:
total += x
# 快速方法(內建函數)
total = sum(data) # 更快、更簡潔
- 索引邊界問題
data = [1, 2, 3, 4, 5]
# 長度為 5,有效索引:0, 1, 2, 3, 4
# ❌ 錯誤:索引超出範圍
# print(data[5]) # IndexError!
# ✅ 正確:使用 len() 確保安全
for i in range(len(data)):
print(data[i])
- 列表操作的時間複雜度
lst[i] | O(1) | 直接存取 |
| lst.append(x) | O(1) | 尾部添加 |
| lst.pop() | O(1) | 尾部移除 |
| lst.pop(0) | O(N) | 頭部移除(慢!) |
| x in lst | O(N) | 成員測試 |
| sum(lst) | O(N) | 遍歷求和 |
- 列表生成式的優勢
- 語法簡潔,一行完成
- 執行速度通常更快
- 可讀性更好(對熟練者)
Quiz: 隕石撞擊預警系統
題目:危險隕石識別
月球基地的雷達偵測到 N 顆接近的隕石。每顆隕石都有一個「危險指數」(整數)。你需要:
- 找出危險指數最高的隕石(及其編號)
- 計算平均危險指數(四捨五入到整數)
- 統計有多少顆隕石的危險指數高於平均值
- 列出所有高於平均值的隕石編號
- 第一行:整數 N(隕石數量,1 ≤ N ≤ 100)
- 第二行:N 個整數,用空格分隔,代表每顆隕石的危險指數(0-100)
7
45 78 23 89 56 34 67
輸出範例:
隕石總數:7
最危險隕石:編號 4,危險指數 89
平均危險指數:56
高於平均值:4 顆
高危隕石編號:[2, 4, 5, 7]
💡 提示
- 使用
enumerate()可以同時獲得索引和值 - 先計算平均值,再進行第二次遍歷
- 記得編號從 1 開始(使用者友善)
---
Quiz 解答
import sys
# 讀取隕石數量
n = int(sys.stdin.readline())
# 讀取所有隕石的危險指數
danger_indices = list(map(int, sys.stdin.readline().strip().split()))
# 1. 找出最危險的隕石
max_danger = max(danger_indices)
max_position = danger_indices.index(max_danger) + 1 # 編號從 1 開始
# 2. 計算平均危險指數
average = round(sum(danger_indices) / n)
# 3 & 4. 統計並列出高於平均值的隕石
high_danger_meteors = []
for i, danger in enumerate(danger_indices, start=1):
if danger > average:
high_danger_meteors.append(i)
# 輸出結果
print(f"隕石總數:{n}")
print(f"最危險隕石:編號 {max_position},危險指數 {max_danger}")
print(f"平均危險指數:{average}")
print(f"高於平均值:{len(high_danger_meteors)} 顆")
print(f"高危隕石編號:{high_danger_meteors}")
解答說明
- 找出最大值及其位置
max_danger = max(danger_indices) # 找出最大值
max_position = danger_indices.index(max_danger) # 找出第一次出現的索引
index()方法返回元素第一次出現的索引- 加 1 轉換為使用者友善的編號
- 計算平均值
sum()計算總和- 除以 N 得到平均值
round()四捨五入到整數- 使用 enumerate 進行過濾
enumerate(..., start=1)讓索引從 1 開始- 同時獲得編號和危險指數
- 符合條件的編號加入列表
- 列表生成式的替代寫法
- 時間複雜度:O(N) - 需要遍歷列表 2-3 次
- 空間複雜度:O(N) - 儲存 N 個隕石數據
- 最壞情況:所有隕石都高於平均值,需要儲存 N 個編號
average = round(sum(danger_indices) / n)
for i, danger in enumerate(danger_indices, start=1):
if danger > average:
high_danger_meteors.append(i)
# 更簡潔的寫法
high_danger_meteors = [i for i, d in enumerate(danger_indices, start=1)
if d > average]
效能分析
常見錯誤
❌ 錯誤 1:索引從 1 開始# 錯誤:Python 索引從 0 開始
print(danger_indices[1]) # 這是第二個元素!
❌ 錯誤 2:修改正在遍歷的列表
# 危險:可能導致跳過元素或錯誤
for i in range(len(lst)):
lst.pop(0) # 不要這樣做!
✅ 正確做法:創建新列表
new_lst = [x for x in lst if condition]
---
訓練完成!
恭喜你完成 數據陣列與感測器管理 訓練!