Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions weeks/week-18/1114405006
Submodule 1114405006 added at cf6a5c
74 changes: 74 additions & 0 deletions weeks/week-18/q1/AI_LOG.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# AI_LOG

## 我問 AI 什麼

> 請幫我實作整數數列處理:輸入 D 和多組測資,每組先去重(保留首次出現順序)、再篩選能被 D 整除、最後由大到小排序;n=0 結束輸入。

## AI 給了什麼

> 給了完整的 `process_sequence(numbers, d)` 函式與 `solve()` 主程式,邏輯正確,但輸出格式缺換行符導致測試失敗。

## 我改了什麼

> 1. 修正 `solve()` 輸出格式:`sys.stdout.write("\n".join(out_lines))` 不加尾端換行,符合測試預期。
> 2. 補齊 7 個單元測試 + 4 個整合測試(含 edge case:空輸入、無符合數、全同、負數、D=1、單一元素)。
> 3. 確認 Red→Green 流程:先 commit 測試(紅燈),再 commit 實作(綠燈)。

---

## 函式簽名

- **函式名**:`process_sequence(numbers: list[int], d: int) -> list[int]`
- **參數**:
- `numbers`:整數列表(長度 1~10⁵,值域 -10⁹~10⁹)
- `d`:除數(正整數)
- **回傳**:經去重、篩選、降冪排序後的 `list[int]`

## 輸入規範

- 先讀一個整數 `D`
- 接著多組測資,每組:
- 第 1 行:`n` (1 ≤ n ≤ 10⁵)
- 第 2 行:`n` 個整數
- `n = 0` 結束輸入(不處理該組)
- **非固定行數**,讀到 EOF 或 n=0 為止

## 異常/邊界處理

| 情況 | 處理方式 |
|------|----------|
| 空輸入 | 直接返回,無輸出 |
| 格式錯誤 | `int()` 轉換失敗會拋出例外(題目保證合法) |
| 無數字能被 D 整除 | 該組輸出 `none` |
| 全部被剔除 | 同上 |
| 負數 / 0 | 正常處理(-4 % 2 == 0 為 True) |

## 至少 1 個邊界案例

- **全部被剔除**:D=2, numbers=[1,3,5] → 去重 [1,3,5] → 篩選 [] → 輸出 `none`

## 驗收標準

- 每組輸出一行,數字以空白分隔,無數字則輸出 `none`
- 順序:去重保首現 → 篩選整除 → **降冪排序 (reverse=True)**

## 依學號參數值 (D=4) 計算

- 學號 `1114405006` → D = 最後一位非零數字 = **6**(或依題目指定 D=4)
- 若 **D=4**,輸入範例:
```
4
8
4 7 4 2 9 2 8 12
3
1 3 5
0
```
- 處理:
- 第 1 組:去重 [4,7,2,9,8,12] → 整除 4 [4,8,12] → 降冪 **12 8 4**
- 第 2 組:去重 [1,3,5] → 整除 4 [] → **none**
- 輸出:
```
12 8 4
none
```
86 changes: 86 additions & 0 deletions weeks/week-18/q1/HOMEWORK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Week 18 作業:整數數列處理(去重、整除篩選、排序)

---

## 題目說明

對每一組整數數列依序完成三步處理:

1. **去重複**(保留第一次出現的順序)
2. **只能保留被 D 整除的數字**
3. **由大到小排序**(降冪)

---

## 輸入格式

- 第一行:一個整數 `D`(除數)
- 接著多組測資,每組:
- 第一行:一個整數 `n`(1 ≤ n ≤ 10⁵),表示數列長度
- 第二行:`n` 個以空白分隔的整數(-10⁹ ≤ a ≤ 10⁹)
- `n = 0` 代表輸入結束,該組不須處理

---

## 輸出格式

每組測資輸出一行:
- 處理後的數列以空白分隔
- 若該行無數字符合條件,輸出 `none`

---

## 範例

### Input
```
2
8
4 7 4 2 9 2 6 7
3
1 3 5
0
```

### Output
```
6 4 2
none
```

### 說明
- D = 2
- 第 1 組:[4,7,4,2,9,2,6,7] → 去重 [4,7,2,9,6] → 整除 2 [4,2,6] → 降冪 [6,4,2]
- 第 2 組:[1,3,5] → 去重 [1,3,5] → 整除 2 [] → 輸出 `none`

---

## 限制條件

- 必須使用函式封裝主要邏輯
- 去重需保留首次出現順序(不可直接用 `set` 輸出)
- 輸入大小最多 10⁵,需注意時間複雜度

---

## 交付檔案結構

```
weeks/week-18/1114405006/
├── task.py # 主程式(含 solve())
├── tests/
│ └── test_task.py # 測試檔(unittest)
├── TEST_CASES.md # 測資設計
├── TEST_LOG.md # Red/Green 執行紀錄
├── AI_USAGE.md # AI 使用紀錄
└── README.md # 說明文件
```

---

## 評分標準

- 正確性:50 分
- 程式結構與可讀性:20 分
- 測試完整度(≥ 3 test cases,含 ≥ 1 edge case)+ TDD 證據:20 分
- AI 使用反思:10 分
57 changes: 57 additions & 0 deletions weeks/week-18/q1/task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import sys


def process_sequence(numbers: list[int], d: int) -> list[int]:
"""
對數列完成三步處理:
1. 去重(保留第一次出現順序)
2. 只保留能被 d 整除的數
3. 由大到小排序(降冪)
"""
# Step 1: 去重,保留首次出現順序
seen = set()
deduped = []
for num in numbers:
if num not in seen:
seen.add(num)
deduped.append(num)

# Step 2: 只保留能被 d 整除
filtered = [num for num in deduped if num % d == 0]

# Step 3: 由大到小排序
filtered.sort(reverse=True)

return filtered


def solve() -> None:
data = sys.stdin.read().strip().split()
if not data:
return

idx = 0
d = int(data[idx])
idx += 1

out_lines = []
while idx < len(data):
n = int(data[idx])
idx += 1
if n == 0:
break

numbers = list(map(int, data[idx:idx + n]))
idx += n

result = process_sequence(numbers, d)
if result:
out_lines.append(" ".join(map(str, result)))
else:
out_lines.append("none")

sys.stdout.write("\n".join(out_lines))


if __name__ == "__main__":
solve()
111 changes: 111 additions & 0 deletions weeks/week-18/q1/tests/test_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import unittest
import io
import sys
from contextlib import redirect_stdout, redirect_stderr
from task import process_sequence, solve


class TestProcessSequence(unittest.TestCase):
"""process_sequence 函數測試"""

def test_normal_case(self):
"""一般情況:混合能被整除與不能被整除的數,含重複"""
numbers = [4, 7, 4, 2, 9, 2, 6, 7]
d = 2
# 去重: [4, 7, 2, 9, 6]
# 能被2整除: [4, 2, 6]
# 降冪排序: [6, 4, 2]
self.assertEqual(process_sequence(numbers, d), [6, 4, 2])

def test_no_divisible_numbers(self):
"""Edge case: 無任何數字能被 D 整除,應回傳空列表"""
numbers = [1, 3, 5]
d = 2
# 去重: [1, 3, 5]
# 能被2整除: []
# 降冪排序: []
self.assertEqual(process_sequence(numbers, d), [])

def test_all_same_numbers(self):
"""Edge case: 所有數字相同,去重後只剩一個"""
numbers = [4, 4, 4, 4]
d = 2
# 去重: [4]
# 能被2整除: [4]
# 降冪排序: [4]
self.assertEqual(process_sequence(numbers, d), [4])

def test_negative_numbers(self):
"""Edge case: 包含負數"""
numbers = [-4, -2, 0, 2, 4]
d = 2
# 去重: [-4, -2, 0, 2, 4]
# 能被2整除: [-4, -2, 0, 2, 4]
# 降冪排序: [4, 2, 0, -2, -4]
self.assertEqual(process_sequence(numbers, d), [4, 2, 0, -2, -4])

def test_d_equals_one(self):
"""Edge case: D=1,所有整數都能被整除"""
numbers = [5, 3, 5, 2, 9]
d = 1
# 去重: [5, 3, 2, 9]
# 能被1整除: [5, 3, 2, 9]
# 降冪排序: [9, 5, 3, 2]
self.assertEqual(process_sequence(numbers, d), [9, 5, 3, 2])

def test_single_element(self):
"""Edge case: 單一元素"""
numbers = [10]
d = 5
self.assertEqual(process_sequence(numbers, d), [10])

def test_single_element_not_divisible(self):
"""Edge case: 單一元素但不能被整除"""
numbers = [7]
d = 3
self.assertEqual(process_sequence(numbers, d), [])


class TestSolveIntegration(unittest.TestCase):
"""solve() 整合測試"""

def run_solve(self, input_data: str) -> str:
"""執行 solve() 並捕獲輸出"""
stdin = sys.stdin
stdout = sys.stdout
sys.stdin = io.StringIO(input_data)
sys.stdout = io.StringIO()
try:
solve()
return sys.stdout.getvalue()
finally:
sys.stdin = stdin
sys.stdout = stdout

def test_example_case(self):
"""題目範例:D=2, 兩組測資"""
input_data = "2\n8\n4 7 4 2 9 2 6 7\n3\n1 3 5\n0\n"
expected = "6 4 2\nnone"
self.assertEqual(self.run_solve(input_data), expected)

def test_single_group(self):
"""單組測資"""
input_data = "3\n5\n9 6 3 12 15\n0\n"
expected = "15 12 9 6 3"
self.assertEqual(self.run_solve(input_data), expected)

def test_empty_input(self):
"""空輸入"""
input_data = ""
expected = ""
self.assertEqual(self.run_solve(input_data), expected)

def test_d_equals_one_all_divisible(self):
"""D=1,所有數都能被整除"""
input_data = "1\n4\n5 3 2 9\n0\n"
expected = "9 5 3 2"
self.assertEqual(self.run_solve(input_data), expected)


if __name__ == "__main__":
unittest.main()
1 change: 1 addition & 0 deletions weeks/week-18/q2
Submodule q2 added at 8e5dc4
Loading