🌙 L1: 月球基地訓練

A3: 月球感測器陣列:數據容器與列表操作

⏱️ 預計時間:3-4 小時 🎯 目標級分:1-2 級分 📊 難度:⭐⭐☆☆☆

🚀 任務背景

月球基地配備了數百個感測器,監測溫度、輻射、氣壓等各種數據。作為數據分析員,你需要處理這些大量的感測器讀數。單一變數已經不夠用了,你需要學會使用「數據容器」來管理成批的資訊。

在這個訓練模組中,你將學習:
  • 如何使用列表(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}")

🔍 程式碼解說

關鍵技術點

  1. 內建函數的效能優勢
   # 慢速方法(手動計算)
   total = 0
   for x in data:
       total += x
   
   # 快速方法(內建函數)
   total = sum(data)  # 更快、更簡潔
   
  1. 索引邊界問題
   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])
   
  1. 列表操作的時間複雜度
| 操作 | 時間複雜度 | 說明 | |------|-----------|------| | 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) | 遍歷求和 |
  1. 列表生成式的優勢
  2. 語法簡潔,一行完成
  3. 執行速度通常更快
  4. 可讀性更好(對熟練者)

📝 Quiz: 隕石撞擊預警系統

題目:危險隕石識別

月球基地的雷達偵測到 N 顆接近的隕石。每顆隕石都有一個「危險指數」(整數)。你需要:

  1. 找出危險指數最高的隕石(及其編號)
  2. 計算平均危險指數(四捨五入到整數)
  3. 統計有多少顆隕石的危險指數高於平均值
  4. 列出所有高於平均值的隕石編號
輸入格式:
  • 第一行:整數 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}")

解答說明

  1. 找出最大值及其位置
   max_danger = max(danger_indices)  # 找出最大值
   max_position = danger_indices.index(max_danger)  # 找出第一次出現的索引
   
  • index() 方法返回元素第一次出現的索引
  • 加 1 轉換為使用者友善的編號
  1. 計算平均值
  2.    average = round(sum(danger_indices) / n)
       
    • sum() 計算總和
    • 除以 N 得到平均值
    • round() 四捨五入到整數
    1. 使用 enumerate 進行過濾
    2.    for i, danger in enumerate(danger_indices, start=1):
             if danger > average:
                 high_danger_meteors.append(i)
         
      • enumerate(..., start=1) 讓索引從 1 開始
      • 同時獲得編號和危險指數
      • 符合條件的編號加入列表
      1. 列表生成式的替代寫法
      2.    # 更簡潔的寫法
           high_danger_meteors = [i for i, d in enumerate(danger_indices, start=1) 
                                  if d > average]
           

        效能分析

        • 時間複雜度:O(N) - 需要遍歷列表 2-3 次
        • 空間複雜度:O(N) - 儲存 N 個隕石數據
        • 最壞情況:所有隕石都高於平均值,需要儲存 N 個編號

        常見錯誤

        錯誤 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]
        

        ---

🎉

訓練完成!

恭喜你完成 數據陣列與感測器管理 訓練!