# 教案：第05节 —— 集合 set

---

## 元信息

| 项目 | 内容 |
|------|------|
| **课程编号** | G3_第05节 |
| **GESP等级** | **三级**（GESP Python 三级考点） |
| **适用年龄** | 10-12 岁（算法入门阶段） |
| **核心知识点** | set 创建 {}、add/remove/discard、pop 随机弹出、去重特性 |
| **记忆钩子** | "set = 自动去重盒子 add加 remove删 discard安全删 pop随机弹" |
| **身体锚点** | ① 创建（双手画圈） ② 去重（筛选手势） ③ 弹出（抽盲盒动作） |

---

## 课程目标

1. **掌握** set 的两种创建方式：set() 和 {}
2. **理解** 集合的三大特性：无序、不重复、可变
3. **熟练** 集合的增删操作：add、remove、discard、pop
4. **运用** 集合的去重特性解决实际问题

---

## 五段式 60 分钟教学流程

---

### 第一段：导入（00:00 - 10:00）—— "重复的东西太多了！"

#### 教师活动

| 时间 | 活动内容 | 教学方式 |
|------|---------|---------|
| 0-3min | 拿出一个袋子，里面装了很多写有数字的纸条（有重复），问："怎么最快知道有哪些数字？" | 实物演示 |
| 3-6min | "Python 也有一个'神奇袋子'——set（集合）。往里丢东西，重复的自动消失！" | 引出概念 |
| 6-10min | 代码演示：列表去重 set([1,2,2,3]) → {1,2,3}，让学生直观看到去重效果 | 代码展示 |

#### 导入代码

```python
# 列表有重复的问题
lst = [1, 2, 2, 3]
print("原始列表:", lst)       # [1, 2, 2, 3]

# 转 set 自动去重
s = set(lst)
print("转set后:", s)           # {1, 2, 3}
```

#### 生活类比

> **set = 自动去重盒子**
> 往盒子里丢重复的东西，只保留一份！
> 就像你的书包里有多支同样的笔，只需要知道"有哪些笔"，不需要知道有几支。

#### 身体锚点

> **【身体锚点 — 去重盒子】**
> 双手做捧盒子动作，往里面放东西的手势。
> "红色铅笔放进去→蓝色铅笔放进去→红色铅笔再放进去→咦，已经有了，自动忽略！"
> 双手摊开："看，盒子里只有一份红色铅笔、一份蓝色铅笔。"

---

### 第二段：知识点精讲（10:00 - 30:00）

#### 2.1 创建集合（5min）

**方式一：使用 set()**
```python
s1 = set([1, 2, 3])        # 列表 → 集合
s2 = set("hello")           # 字符串 → 集合（每个字符变成元素）
s3 = set()                  # 空集合（注意：只能用 set() 创建空集合！）

print("s1:", s1)            # {1, 2, 3}
print("s2:", s2)            # {'h', 'e', 'l', 'o'} —— 自动去重且无序
print("s3:", s3)            # set()
```

**方式二：使用花括号 {}**
```python
s4 = {1, 2, 3}
s5 = {"apple", "banana", "orange"}
print("s4:", s4)            # {1, 2, 3}
print("s5:", s5)            # 无序输出
```

**重要陷阱：{} 创建的是空字典，不是空集合！**
```python
wrong = {}
print("type({}):", type(wrong))    # <class 'dict'>

correct = set()
print("type(set()):", type(correct))  # <class 'set'>
```

**记忆口诀：**
```
set()或{}  花括号创建集合
空集必须用 set()，用 {} 得到的是空字典！
```

#### 2.2 add() 添加元素（4min）

```python
fruits = {"apple", "banana"}
print("初始集合:", fruits)

fruits.add("orange")
print("添加orange后:", fruits)

# add() 重复添加不会报错，也不会增加
fruits.add("apple")           # apple 已存在，被忽略
print("再次添加apple后:", fruits)  # 没变化
```

**应用：收集不重复的用户输入**
```python
inputs = set()
inputs.add("Python")
inputs.add("Java")
inputs.add("Python")          # 重复，被忽略
print("收集的语言:", inputs)   # {'Java', 'Python'}
```

**比喻：** add 像往盒子里扔一个球，重复的球扔不进去，因为已经有了！

#### 2.3 remove() 删除元素（4min）

```python
colors = {"red", "blue", "green", "yellow"}
print("初始集合:", colors)

colors.remove("blue")
print("删除blue后:", colors)

# remove() 删除不存在的元素会报错！
try:
    colors.remove("pink")     # pink 不在集合中
except KeyError as e:
    print(f"报错啦！KeyError: {e}")
```

**注意：** remove 是精准删除指定元素，如果元素不存在，直接崩溃报错！

#### 2.4 discard() 安全删除（4min）

```python
fruits = {"apple", "banana", "orange"}
fruits.discard("banana")
print("删除banana后:", fruits)

# discard() 删除不存在的元素——安全！
fruits.discard("grape")         # grape 不在集合中
print("删除不存在的grape后:", fruits)  # 没有任何变化
print("程序正常运行，没有报错！")
```

**remove vs discard 对比：**

| 方法 | 元素存在时 | 元素不存在时 |
|------|-----------|-------------|
| remove(元素) | 正常删除 | 报错 KeyError |
| discard(元素) | 正常删除 | 什么都不发生（安全） |

**记忆钩子：** discard 安全删 —— 有就删，没有拉倒，绝不报错！

#### 2.5 pop() 随机弹出一个元素（3min）

```python
nums = {10, 20, 30, 40, 50}
print("原始集合:", nums)

popped = nums.pop()
print(f"弹出了: {popped}")
print("剩余集合:", nums)

# pop() 空集合会报错
empty_set = set()
try:
    empty_set.pop()
except KeyError as e:
    print(f"空集合pop报错: {e}")
```

**实用场景：随机处理任务队列**
```python
tasks = {"任务A", "任务B", "任务C", "任务D"}
print("随机处理任务：")
while tasks:
    task = tasks.pop()
    print(f"  处理: {task}")
print("所有任务处理完毕！")
```

**记忆钩子：** pop 随机弹 —— 像抽盲盒，弹出哪个是哪个。集合空了还 pop 会报错！

---

### 第三段：演示（30:00 - 40:00）—— "set 实战演示"

#### 演示 1：颜色去重

```python
colors_set = {"red", "blue", "red"}
print("colors_set:", colors_set)
# 输出: {'red', 'blue'} —— "red" 被去重只剩一个！
```

#### 演示 2：多种数据去重

```python
# 数字去重
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
unique_nums = set(numbers)
print("数字去重:", sorted(unique_nums))  # [1, 2, 3, 4, 5, 6, 9]

# 字符串去重
words = ["hello", "world", "hello", "python", "world"]
unique_words = set(words)
print("单词去重:", unique_words)

# 字符去重
text = "aabbccdd"
unique_chars = set(text)
print("字符去重:", unique_chars)          # {'a', 'b', 'c', 'd'}
```

#### 演示 3：综合操作

```python
s = set()
s.add("red")
s.add("green")
s.add("red")         # 被忽略
s.discard("green")
print("最终集合:", s)  # {'red'}
```

#### 演示 4：去重应用——统计文章用词

```python
article = "python is fun and python is powerful"
words = article.split()
unique_words = set(words)
print(f"总词数: {len(words)}")
print(f"不重复词数: {len(unique_words)}")
print(f"用到的词: {unique_words}")
```

**教学要点：** 通过 split() 拆分字符串，用 set 去重统计文章中用到了哪些不同的词。

---

### 第四段：实操练习（40:00 - 55:00）

#### 练习 1：创建集合去重（5min）

```
题目：给定列表 [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
      用 set 去重，并打印出去重后 sorted 的结果
```

**参考答案：**
```python
nums = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
unique = set(nums)
print(sorted(unique))  # [1, 2, 3, 4, 5, 6, 9]
```

#### 练习 2：操作填空（5min）

```
补全代码，使其输出 {1, 2}
s = {1, 2, 3}
s.____(2)          # 添加2（已有，忽略）
s.____(3)          # 删除3
print(s)            # 预期: {1, 2}
```

**答案：** add, remove（或 discard）

#### 练习 3：remove vs discard 选择（5min）

```
题目：用户输入一个数字，尝试从集合 {10, 20, 30, 40, 50} 中删除。
      应该用 remove 还是 discard？为什么？
```

**参考答案：**
```python
nums = {10, 20, 30, 40, 50}

n = int(input("请输入要删除的数字: "))
# 用 discard 更安全，因为用户可能输入不存在的数字
nums.discard(n)
print(f"删除后: {nums}")
# 如果使用 remove，输入不存在数字会报错！
```

---

### 第五段：小测（55:00 - 60:00）

#### 题目 1（选择）
`set([1, 2, 2, 3])` 的结果是？
A. [1, 2, 2, 3]
B. {1, 2, 3}
C. {1, 2, 2, 3}
D. [1, 2, 3]

**答案：B**

#### 题目 2（选择）
下面哪个方法在删除不存在的元素时会报错？
A. discard()
B. remove()
C. pop()
D. add()

**答案：B**

#### 题目 3（选择）
`{}` 创建的是什么？
A. 空集合
B. 空字典
C. 空列表
D. 空元组

**答案：B**（{} 创建空字典，空集合必须用 set()）

#### 题目 4（判断）
集合中的元素是有序的。

**答案：** 错（集合是无序的，每次遍历顺序可能不同）

#### 题目 5（填空）
从集合中随机弹出一个元素的方法是 ____

**答案：** pop()

---

## 板书设计

```
+-------------------------------------------------------+
|       第05节  集合 set                                  |
+-------------------------------------------------------+

  创建集合：
  set([1, 2, 3])   或   {1, 2, 3}
  空集合：set()           {} 是空字典！

  集合特性：
  . 无序 —— 元素没有固定顺序
  . 不重复 —— 自动去重
  . 可变 —— 可以增删元素

  操作方法：
  add(元素)    添加（重复被忽略）
  remove(元素) 删除（不存在报错）
  discard(元素) 安全删除（不存在不报错）
  pop()        随机弹出（空集合报错）

  记忆钩子：
  "set = 自动去重盒子"
  "add加 remove删 discard安全删 pop随机弹"
---

## 课后延伸

| 项目 | 内容 |
|------|------|
| 课后练习 | 课后练习_第05节.md |
| 预习内容 | 第05节 集合运算 |
| 拓展挑战 | 用 set 完成两篇文章的词汇对比（共同词、独有词） |
| 家长沟通 | 今天学习了 Python 的集合 set，孩子可以用它来去重和快速查找 |

---

## 教学反思

| 维度 | 记录 |
|------|------|
| 学生掌握率 | 预计 80% 学生能掌握基本操作 |
| 常见困惑 | {} 创建空集合还是空字典容易混淆 |
| 改进方向 | 增加 remove 和 discard 的对比练习 |
| 备注 | 强调 set 无序特性的实际影响（不能用下标访问） |
```
