Appearance
字典与集合
字典(Dictionary)和集合(Set)是Python中两种重要的数据结构。字典用于存储键值对,集合用于存储不重复的元素。本章将详细介绍这两种数据结构的使用方法。
字典(Dictionary)
什么是字典
字典是Python中一种可变的、无序的键值对集合。每个键值对用冒号:分隔,键值对之间用逗号,分隔,整个字典用花括号{}包围。
python
# 创建一个简单的字典
# 字典存储的是键值对(key-value pair)
student = {
"name": "张三", # 键是"name",值是"张三"
"age": 20, # 键是"age",值是20
"city": "北京" # 键是"city",值是"北京"
}
print(student) # 输出: {'name': '张三', 'age': 20, 'city': '北京'}
print(type(student)) # 输出: <class 'dict'>字典的特点
python
# 字典的特点演示
# 1. 键必须是不可变类型(如字符串、数字、元组)
valid_dict = {
"name": "张三", # 字符串作为键 - 正确
1: "数字键", # 数字作为键 - 正确
(1, 2): "元组键" # 元组作为键 - 正确
}
print(valid_dict)
# 2. 键必须唯一,重复的键会覆盖
duplicate_dict = {
"name": "张三",
"name": "李四" # 重复的键,后面的值会覆盖前面的
}
print(duplicate_dict) # 输出: {'name': '李四'}
# 3. 值可以是任意类型
mixed_dict = {
"string": "字符串",
"number": 123,
"list": [1, 2, 3],
"dict": {"a": 1, "b": 2},
"tuple": (1, 2, 3),
"set": {1, 2, 3}
}
print(mixed_dict)创建字典
python
# 创建字典的多种方式
# 方式1:使用花括号 {}
dict1 = {"name": "张三", "age": 20}
print(f"方式1: {dict1}")
# 方式2:使用 dict() 构造函数
dict2 = dict(name="李四", age=25) # 使用关键字参数
print(f"方式2: {dict2}")
# 方式3:使用 dict() 传入键值对列表
dict3 = dict([("name", "王五"), ("age", 30)])
print(f"方式3: {dict3}")
# 方式4:创建空字典
empty_dict1 = {}
empty_dict2 = dict()
print(f"空字典1: {empty_dict1}, 类型: {type(empty_dict1)}")
print(f"空字典2: {empty_dict2}, 类型: {type(empty_dict2)}")
# 方式5:使用字典推导式
squares = {x: x**2 for x in range(1, 6)}
print(f"字典推导式: {squares}") # 输出: {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# 方式6:使用 fromkeys() 创建具有相同值的字典
keys = ["a", "b", "c"]
dict6 = dict.fromkeys(keys, 0) # 所有键的值都设为0
print(f"fromkeys: {dict6}") # 输出: {'a': 0, 'b': 0, 'c': 0}访问字典元素
python
# 访问字典中的值
student = {"name": "张三", "age": 20, "city": "北京"}
# 方式1:使用方括号 []
print(f"姓名: {student['name']}") # 输出: 张三
print(f"年龄: {student['age']}") # 输出: 20
# 注意:如果键不存在,会报错
# print(student['gender']) # KeyError: 'gender'
# 方式2:使用 get() 方法(推荐)
print(f"姓名: {student.get('name')}") # 输出: 张三
# get() 方法的优势:键不存在时返回 None,不会报错
print(f"性别: {student.get('gender')}") # 输出: None
# 可以指定默认值
print(f"性别: {student.get('gender', '未知')}") # 输出: 未知
# 方式3:获取所有键、值、键值对
print(f"所有键: {student.keys()}") # 输出: dict_keys(['name', 'age', 'city'])
print(f"所有值: {student.values()}") # 输出: dict_values(['张三', 20, '北京'])
print(f"所有键值对: {student.items()}") # 输出: dict_items([('name', '张三'), ('age', 20), ('city', '北京')])
# 将它们转换为列表使用
keys_list = list(student.keys())
values_list = list(student.values())
items_list = list(student.items())
print(f"键列表: {keys_list}")
print(f"值列表: {values_list}")
print(f"键值对列表: {items_list}")修改字典
python
# 修改字典内容
student = {"name": "张三", "age": 20}
# 1. 添加/修改单个键值对
student["city"] = "北京" # 添加新键值对
student["age"] = 21 # 修改已有键的值
print(f"修改后: {student}")
# 2. 使用 update() 方法批量更新
student.update({
"gender": "男", # 添加新键
"age": 22 # 修改已有键
})
print(f"update后: {student}")
# update() 也可以传入关键字参数
student.update(email="zhangsan@example.com", phone="12345678901")
print(f"再次update后: {student}")
# 3. 删除元素
# 使用 del 关键字
del student["phone"]
print(f"删除phone后: {student}")
# 使用 pop() 方法(删除并返回值)
age = student.pop("age")
print(f"删除的年龄: {age}")
print(f"pop后: {student}")
# pop() 可以指定默认值,键不存在时不报错
result = student.pop("height", "不存在")
print(f"pop不存在的键: {result}")
# 4. 删除并返回最后一个键值对
student["age"] = 20
student["height"] = 175
last_item = student.popitem()
print(f"删除的最后一项: {last_item}")
print(f"popitem后: {student}")
# 5. 清空字典
student_copy = student.copy()
student_copy.clear()
print(f"清空后: {student_copy}")字典的遍历
python
# 遍历字典的多种方式
student = {"name": "张三", "age": 20, "city": "北京"}
# 1. 遍历键(默认行为)
print("=== 遍历键 ===")
for key in student:
print(f"键: {key}")
# 显式遍历键
print("\n=== 显式遍历键 ===")
for key in student.keys():
print(f"键: {key}")
# 2. 遍历值
print("\n=== 遍历值 ===")
for value in student.values():
print(f"值: {value}")
# 3. 遍历键值对(推荐)
print("\n=== 遍历键值对 ===")
for key, value in student.items():
print(f"{key}: {value}")
# 4. 使用 enumerate 获取索引
print("\n=== 带索引遍历 ===")
for index, (key, value) in enumerate(student.items()):
print(f"第{index + 1}个: {key} = {value}")
# 5. 在遍历时修改字典(需要创建副本)
print("\n=== 安全修改遍历 ===")
scores = {"张三": 85, "李四": 92, "王五": 78}
# 错误做法:直接遍历修改
# for name in scores:
# if scores[name] < 80:
# del scores[name] # RuntimeError
# 正确做法:遍历副本
for name in list(scores.keys()):
if scores[name] < 80:
del scores[name]
print(f"删除低分后: {scores}")字典常用方法
python
# 字典常用方法详解
# 1. setdefault() - 获取值,不存在则设置默认值
person = {"name": "张三"}
# 如果键存在,返回对应的值
name = person.setdefault("name", "默认名")
print(f"name: {name}") # 输出: 张三
# 如果键不存在,添加键值对并返回默认值
age = person.setdefault("age", 20)
print(f"age: {age}") # 输出: 20
print(f"person: {person}") # 输出: {'name': '张三', 'age': 20}
# 2. copy() - 浅拷贝
original = {"a": 1, "b": [1, 2, 3]}
copied = original.copy()
copied["a"] = 100
copied["b"].append(4) # 注意:列表是引用,会影响原字典
print(f"原字典: {original}") # b的列表也被修改了
print(f"拷贝字典: {copied}")
# 3. 深拷贝
import copy
original2 = {"a": 1, "b": [1, 2, 3]}
deep_copied = copy.deepcopy(original2)
deep_copied["b"].append(4)
print(f"原字典(深拷贝): {original2}") # 不受影响
print(f"深拷贝字典: {deep_copied}")
# 4. 判断键是否存在
student = {"name": "张三", "age": 20}
print(f"'name' in student: {'name' in student}") # True
print(f"'city' in student: {'city' in student}") # False
print(f"'name' not in student: {'name' not in student}") # False
# 5. 获取字典长度
print(f"字典长度: {len(student)}") # 输出: 2
# 6. 合并字典(Python 3.9+)
dict_a = {"a": 1, "b": 2}
dict_b = {"c": 3, "d": 4}
# 使用 | 运算符
merged = dict_a | dict_b
print(f"合并结果: {merged}")
# 使用 |= 运算符原地合并
dict_a |= dict_b
print(f"dict_a合并后: {dict_a}")
# Python 3.5+ 使用 ** 解包
dict_c = {"a": 1, "b": 2}
dict_d = {"c": 3, "d": 4}
merged_unpack = {**dict_c, **dict_d}
print(f"解包合并: {merged_unpack}")嵌套字典
python
# 嵌套字典的使用
# 1. 字典中嵌套字典
students = {
"张三": {
"age": 20,
"gender": "男",
"scores": {
"math": 90,
"english": 85
}
},
"李四": {
"age": 21,
"gender": "女",
"scores": {
"math": 88,
"english": 92
}
}
}
# 访问嵌套数据
print(f"张三的年龄: {students['张三']['age']}")
print(f"张三的数学成绩: {students['张三']['scores']['math']}")
# 遍历嵌套字典
print("\n=== 学生信息 ===")
for name, info in students.items():
print(f"\n学生: {name}")
print(f" 年龄: {info['age']}")
print(f" 性别: {info['gender']}")
print(f" 成绩:")
for subject, score in info['scores'].items():
print(f" {subject}: {score}")
# 2. 字典中嵌套列表
class_info = {
"class_name": "一班",
"students": ["张三", "李四", "王五"],
"teachers": ["王老师", "李老师"]
}
print(f"\n班级: {class_info['class_name']}")
print(f"学生列表: {class_info['students']}")
# 添加新学生
class_info['students'].append("赵六")
print(f"添加后学生列表: {class_info['students']}")集合(Set)
什么是集合
集合是一个无序的、不重复的元素集合。集合使用花括号{}创建,或者使用set()函数。
python
# 创建集合
# 方式1:使用花括号
fruits = {"苹果", "香蕉", "橙子"}
print(f"水果集合: {fruits}")
print(f"类型: {type(fruits)}")
# 方式2:使用 set() 函数
numbers = set([1, 2, 3, 4, 5])
print(f"数字集合: {numbers}")
# 方式3:创建空集合(注意:不能用 {})
empty_set = set() # 正确
# empty_set = {} # 错误!这会创建空字典
print(f"空集合: {empty_set}, 类型: {type(empty_set)}")
# 方式4:使用集合推导式
squares = {x**2 for x in range(1, 6)}
print(f"平方数集合: {squares}")
# 集合自动去重
duplicates = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4}
print(f"去重后: {duplicates}") # 输出: {1, 2, 3, 4}集合的特点
python
# 集合的特点演示
# 1. 元素不重复
set1 = {1, 2, 3, 2, 1}
print(f"自动去重: {set1}") # 输出: {1, 2, 3}
# 2. 元素必须不可变
valid_set = {1, "hello", (1, 2)} # 数字、字符串、元组都可以
print(f"有效集合: {valid_set}")
# 列表不能作为集合元素(因为列表是可变的)
# invalid_set = {1, 2, [3, 4]} # TypeError
# 3. 集合是无序的
set2 = {3, 1, 4, 1, 5, 9}
print(f"无序集合: {set2}") # 输出顺序可能不同
# 4. 不能通过索引访问
# print(set2[0]) # TypeError: 'set' object is not subscriptable
# 5. 集合本身是可变的,但可以创建不可变集合
frozen = frozenset([1, 2, 3])
print(f"不可变集合: {frozen}")
# frozen.add(4) # AttributeError: 'frozenset' object has no attribute 'add'集合的基本操作
python
# 集合的基本操作
fruits = {"苹果", "香蕉", "橙子"}
# 1. 添加元素
fruits.add("葡萄")
print(f"添加后: {fruits}")
# 添加已存在的元素不会有变化
fruits.add("苹果")
print(f"添加重复元素后: {fruits}")
# 2. 删除元素
# remove() - 元素不存在会报错
fruits.remove("香蕉")
print(f"remove后: {fruits}")
# discard() - 元素不存在不会报错
fruits.discard("西瓜") # 不报错
print(f"discard后: {fruits}")
# pop() - 随机删除一个元素
popped = fruits.pop()
print(f"删除的元素: {popped}")
print(f"pop后: {fruits}")
# 3. 清空集合
fruits_copy = fruits.copy()
fruits_copy.clear()
print(f"清空后: {fruits_copy}")
# 4. 获取集合长度
print(f"集合长度: {len(fruits)}")
# 5. 判断元素是否存在
fruits.add("苹果")
fruits.add("香蕉")
print(f"'苹果' in fruits: {'苹果' in fruits}") # True
print(f"'西瓜' in fruits: {'西瓜' in fruits}") # False集合的数学运算
python
# 集合的数学运算
A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}
# 1. 并集(union 或 |)
print(f"并集(union): {A.union(B)}")
print(f"并集(|): {A | B}")
# 2. 交集(intersection 或 &)
print(f"交集(intersection): {A.intersection(B)}")
print(f"交集(&): {A & B}")
# 3. 差集(difference 或 -)
print(f"A-B差集(difference): {A.difference(B)}")
print(f"A-B差集(-): {A - B}")
print(f"B-A差集: {B - A}")
# 4. 对称差集(symmetric_difference 或 ^)
# 对称差集 = 并集 - 交集
print(f"对称差集: {A.symmetric_difference(B)}")
print(f"对称差集(^): {A ^ B}")
# 5. 判断子集和超集
C = {1, 2, 3}
D = {1, 2, 3, 4, 5}
print(f"\nC是D的子集: {C.issubset(D)}") # True
print(f"C <= D: {C <= D}") # True
print(f"C < D (真子集): {C < D}") # True
print(f"D是C的超集: {D.issuperset(C)}") # True
print(f"D >= C: {D >= C}") # True
print(f"D > C (真超集): {D > C}") # True
# 6. 判断是否不相交
E = {1, 2, 3}
F = {4, 5, 6}
print(f"\nE和F不相交: {E.isdisjoint(F)}") # True
G = {1, 2, 3}
H = {3, 4, 5}
print(f"G和H不相交: {G.isdisjoint(H)}") # False(有公共元素3)集合的更新操作
python
# 集合的更新操作(原地修改)
A = {1, 2, 3}
B = {3, 4, 5}
# 1. update() - 并集更新
A_copy = A.copy()
A_copy.update(B)
print(f"update后: {A_copy}") # {1, 2, 3, 4, 5}
# 使用 |= 运算符
A_copy2 = A.copy()
A_copy2 |= B
print(f"|= 后: {A_copy2}")
# 2. intersection_update() - 交集更新
A_copy = A.copy()
A_copy.intersection_update(B)
print(f"intersection_update后: {A_copy}") # {3}
# 使用 &= 运算符
A_copy2 = A.copy()
A_copy2 &= B
print(f"&= 后: {A_copy2}")
# 3. difference_update() - 差集更新
A_copy = A.copy()
A_copy.difference_update(B)
print(f"difference_update后: {A_copy}") # {1, 2}
# 使用 -= 运算符
A_copy2 = A.copy()
A_copy2 -= B
print(f"-= 后: {A_copy2}")
# 4. symmetric_difference_update() - 对称差集更新
A_copy = A.copy()
A_copy.symmetric_difference_update(B)
print(f"symmetric_difference_update后: {A_copy}") # {1, 2, 4, 5}
# 使用 ^= 运算符
A_copy2 = A.copy()
A_copy2 ^= B
print(f"^= 后: {A_copy2}")集合推导式
python
# 集合推导式
# 基本语法:{expression for item in iterable if condition}
# 1. 创建平方数集合
squares = {x**2 for x in range(1, 6)}
print(f"平方数集合: {squares}")
# 2. 带条件的集合推导式
even_squares = {x**2 for x in range(1, 11) if x % 2 == 0}
print(f"偶数的平方: {even_squares}")
# 3. 字符串处理
text = "Hello World"
unique_chars = {char.lower() for char in text if char.isalpha()}
print(f"唯一字母: {unique_chars}")
# 4. 从列表创建集合并过滤
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
odd_set = {x for x in numbers if x % 2 != 0}
print(f"奇数集合: {odd_set}")
# 5. 嵌套推导式
# 创建所有可能的坐标点(去重)
points = {(x, y) for x in range(3) for y in range(3)}
print(f"坐标点集合: {points}")集合的实际应用
python
# 集合的实际应用场景
# 1. 去除列表中的重复元素
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique_numbers = list(set(numbers))
print(f"去重后: {unique_numbers}")
# 保持原顺序的去重
from collections import OrderedDict
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3]
unique_ordered = list(dict.fromkeys(numbers))
print(f"保持顺序去重: {unique_ordered}")
# 2. 查找两个列表的共同元素
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
common = list(set(list1) & set(list2))
print(f"共同元素: {common}")
# 3. 查找只在其中一个列表中的元素
only_in_list1 = list(set(list1) - set(list2))
only_in_list2 = list(set(list2) - set(list1))
print(f"只在list1中: {only_in_list1}")
print(f"只在list2中: {only_in_list2}")
# 4. 判断列表是否有重复元素
def has_duplicates(lst):
return len(lst) != len(set(lst))
print(f"[1,2,3]有重复: {has_duplicates([1, 2, 3])}") # False
print(f"[1,2,2,3]有重复: {has_duplicates([1, 2, 2, 3])}") # True
# 5. 权限验证
user_permissions = {"read", "write", "execute"}
required_permissions = {"read", "write"}
# 检查用户是否拥有所有必需权限
has_all = required_permissions.issubset(user_permissions)
print(f"拥有所有必需权限: {has_all}")
# 检查用户是否拥有任意一个必需权限
has_any = bool(user_permissions & required_permissions)
print(f"拥有任意必需权限: {has_any}")字典与集合的比较
python
# 字典与集合的比较
# 1. 创建方式
my_dict = {"a": 1, "b": 2} # 字典:键值对
my_set = {1, 2, 3} # 集合:只有值
# 2. 空对象的创建
empty_dict = {} # 空字典
empty_set = set() # 空集合(注意:{} 是空字典)
print(f"空字典类型: {type(empty_dict)}") # <class 'dict'>
print(f"空集合类型: {type(empty_set)}") # <class 'set'>
# 3. 访问方式
my_dict = {"name": "张三", "age": 20}
my_set = {1, 2, 3}
print(f"字典访问: {my_dict['name']}") # 通过键访问
# print(my_set[0]) # 集合不能通过索引访问
# 4. 可变性
# 字典和集合都是可变的
my_dict["city"] = "北京"
my_set.add(4)
print(f"修改后字典: {my_dict}")
print(f"修改后集合: {my_set}")
# 5. 性能特点
# 字典和集合的查找时间复杂度都是 O(1)
# 列表的查找时间复杂度是 O(n)
import time
# 测试查找性能
large_list = list(range(100000))
large_set = set(range(100000))
large_dict = {i: i for i in range(100000)}
# 列表查找
start = time.time()
99999 in large_list
list_time = time.time() - start
# 集合查找
start = time.time()
99999 in large_set
set_time = time.time() - start
# 字典查找
start = time.time()
99999 in large_dict
dict_time = time.time() - start
print(f"\n查找性能比较:")
print(f"列表查找时间: {list_time:.6f}秒")
print(f"集合查找时间: {set_time:.6f}秒")
print(f"字典查找时间: {dict_time:.6f}秒")使用场景总结
| 数据结构 | 特点 | 适用场景 |
|---|---|---|
| 字典 | 键值对,快速查找 | 存储配置信息、计数器、映射关系 |
| 集合 | 无序不重复,快速判断存在 | 去重、集合运算、权限验证 |
python
# 实际应用示例
# 1. 使用字典作为计数器
text = "hello world"
counter = {}
for char in text:
counter[char] = counter.get(char, 0) + 1
print(f"字符计数: {counter}")
# 使用 collections.Counter 更简洁
from collections import Counter
counter = Counter(text)
print(f"Counter结果: {counter}")
# 2. 使用字典存储配置
config = {
"database": {
"host": "localhost",
"port": 3306,
"name": "mydb"
},
"app": {
"debug": True,
"port": 8080
}
}
print(f"数据库配置: {config['database']}")
# 3. 使用集合进行数据清洗
raw_data = ["张三", "李四", "张三", "王五", "李四", "赵六"]
clean_data = list(set(raw_data))
print(f"清洗后数据: {clean_data}")
# 4. 使用集合进行标签匹配
article_tags = {"Python", "编程", "教程"}
user_interests = {"Python", "Java", "前端"}
# 找到用户感兴趣的文章
matching_tags = article_tags & user_interests
print(f"匹配的标签: {matching_tags}")
# 判断文章是否与用户兴趣相关
is_relevant = bool(matching_tags)
print(f"文章是否相关: {is_relevant}")小结
本章学习了Python中两种重要的数据结构:
字典(Dictionary):
- 使用键值对存储数据
- 键必须不可变且唯一
- 支持快速查找、添加、删除
- 适合存储结构化数据
集合(Set):
- 存储不重复的元素
- 元素必须不可变
- 支持数学集合运算
- 适合去重和成员判断
掌握字典和集合的使用,将帮助你更高效地处理各种数据处理任务。
