8  数据结构:字符串与字典

8.1 字符串:文本的艺术

想象你在写短信或者聊天,你输入的文字就是字符串。在Python中,字符串是用来处理文本的基本工具。

8.1.1 创建字符串

字符串就像是用引号包起来的文字:

# 三种创建字符串的方式
message1 = 'Hello'           # 单引号
message2 = "Hello"           # 双引号
message3 = """Hello          
World"""                     # 三引号(可以跨多行)

print("单引号:", message1)
print("双引号:", message2)
print("三引号:", message3)
单引号: Hello
双引号: Hello
三引号: Hello          
World

8.1.1.1 处理特殊情况

有时候我们需要在字符串中包含引号,比如:

# 在字符串中包含引号
print("小明说:'今天天气真好!'")  # 在双引号中使用单引号
print('她说:"我同意!"')         # 在单引号中使用双引号

# 使用转义字符 \
print('小红说:\'学Python真有趣!\'')  # 用 \ 来表示引号
小明说:'今天天气真好!'
她说:"我同意!"
小红说:'学Python真有趣!'

8.1.1.2 常用转义字符

  • \n: 换行
  • \t: 制表符(Tab键)
  • \': 单引号
  • \": 双引号
  • \\: 反斜杠
# 转义字符示例
print("姓名\t年龄\t成绩")
print("小明\t16\t95")
print("小红\t15\t92")
print("\n这是新的一行")
姓名  年龄  成绩
小明  16  95
小红  15  92

这是新的一行

8.1.2 字符串操作

8.1.2.1 访问字符串中的字符

字符串就像一串珠子,我们可以通过位置(索引)来访问每个字符:

# 创建一个字符串
name = "Python编程"
print("完整字符串:", name)
print("第一个字符:", name[0])
print("最后一个字符:", name[-1])
print("前三个字符:", name[:3])
print("去掉第一个字符:", name[1:])
完整字符串: Python编程
第一个字符: P
最后一个字符: 程
前三个字符: Pyt
去掉第一个字符: ython编程

8.1.2.2 常用字符串方法

就像文字处理软件中的各种功能,Python提供了许多处理字符串的方法:

# 创建一个示例字符串
text = "  Hello, Python!  "

# 1. 改变大小写
print("原始文本:", text)
print("全部大写:", text.upper())
print("全部小写:", text.lower())
print("首字母大写:", text.title())

# 2. 删除空白
print("删除两端空白:", text.strip())

# 3. 替换内容
print("替换文本:", text.replace("Python", "World"))

# 4. 分割字符串
sentence = "Python,Java,C++,JavaScript"
languages = sentence.split(",")
print("分割后的列表:", languages)

# 5. 合并字符串
print("重新合并:", " | ".join(languages))
原始文本:   Hello, Python!  
全部大写:   HELLO, PYTHON!  
全部小写:   hello, python!  
首字母大写:   Hello, Python!  
删除两端空白: Hello, Python!
替换文本:   Hello, World!  
分割后的列表: ['Python', 'Java', 'C++', 'JavaScript']
重新合并: Python | Java | C++ | JavaScript

8.1.2.3 字符串格式化

想象你在制作一个成绩单模板,需要填入不同的名字和分数:

# 打印成绩单

# 学生信息
name = "小明"
chinese = 95
math = 98
english = 92

# 计算平均分
average = (chinese + math + english) / 3

# 使用f-字符串生成成绩单
card = f"""
=== {name}的成绩单 ===
语文:{chinese}
数学:{math}
英语:{english}
平均分:{average:.1f}
==================
"""

# 显示成绩单
print(card)

=== 小明的成绩单 ===
语文:95分
数学:98分
英语:92分
平均分:95.0分
==================

8.1.2.4 实用技巧

  1. 检查字符串内容
text = "Python123"
print("是否全是字母?", text.isalpha())
print("是否全是数字?", text.isdigit())
print("是否以'Py'开头?", text.startswith("Py"))
print("是否以'123'结尾?", text.endswith("123"))
是否全是字母? False
是否全是数字? False
是否以'Py'开头? True
是否以'123'结尾? True
  1. 查找和计数
message = "Hello, Hello, Python!"
print("'Hello'出现的次数:", message.count("Hello"))
print("'Python'的位置:", message.find("Python"))
'Hello'出现的次数: 2
'Python'的位置: 14

8.1.2.5 练习题

  1. 创建一个简单的用户名检查程序:
    • 检查长度是否在6-12之间
    • 确保只包含字母和数字
    • 检查是否以字母开头

🌟 要点总结

  1. 字符串用引号创建(单引号、双引号或三引号)
  2. 可以用索引和切片访问字符串中的字符
  3. 字符串有很多实用的内置方法
  4. f-字符串是最简便的字符串格式化方式
  5. 字符串是不可变的(创建后不能修改)
  6. 使用转义字符处理特殊情况
  7. 字符串方法不会修改原字符串,而是返回新字符串

8.2 字典:键值对的魔法

想象你在图书馆,书架上有很多书。每本书都有一个独特的书名(键)和对应的内容(值)。在Python中,字典就是用来存储这种”键值对”的数据结构。

8.2.1 什么是字典?

字典是Python中一种重要的数据结构,用于存储键值对。字典是无序的,但我们可以通过键来快速访问对应的值。

# 创建一个字典
person = {
    "name": "Alice",
    "age": 20,
    "hobbies": ["reading", "swimming"]
}
print("字典内容:", person)
字典内容: {'name': 'Alice', 'age': 20, 'hobbies': ['reading', 'swimming']}

8.2.2 字典的特点

  • 键值对:字典中的每个元素都是一个键值对,键是唯一的,值可以重复。
  • 无序:字典中的元素没有固定的顺序。
  • 可变:可以随时修改、添加或删除键值对。

8.2.3 访问字典中的值

要访问字典中的值,我们使用键:

# 访问字典中的值
name = person["name"]
print("姓名:", name)

# 访问嵌套字典中的值
hobbies = person["hobbies"]
print("爱好:", hobbies)
姓名: Alice
爱好: ['reading', 'swimming']

如果尝试访问一个不存在的键,Python会抛出KeyError错误。为了避免这种情况,我们可以使用get()方法:

# 使用 get 方法访问字典中的值
age = person.get("age", 18)  # 如果没有找到"age",返回18
print("年龄:", age)

# 访问一个不存在的键
pet = person.get("pet", "没有宠物")
print("宠物:", pet)
年龄: 20
宠物: 没有宠物

8.2.4 修改、添加和删除字典中的元素

我们可以通过键来修改字典中的值,添加新的键值对,或者删除已有的键值对:

# 修改字典中的值
person["age"] = 21
print("修改后的年龄:", person["age"])

# 添加新的键值对
person["pet"] = "dog"
print("添加后的字典:", person)

# 删除键值对
del person["hobbies"]
print("删除后的字典:", person)
修改后的年龄: 21
添加后的字典: {'name': 'Alice', 'age': 21, 'hobbies': ['reading', 'swimming'], 'pet': 'dog'}
删除后的字典: {'name': 'Alice', 'age': 21, 'pet': 'dog'}

8.2.5 字典的常用操作

  • 获取所有键:使用keys()方法
  • 获取所有值:使用values()方法
  • 获取所有键值对:使用items()方法
# 获取字典中的所有键
keys = person.keys()
print("所有键:", keys)

# 获取字典中的所有值
values = person.values()
print("所有值:", values)

# 获取字典中的所有键值对
items = person.items()
print("所有键值对:", items)
所有键: dict_keys(['name', 'age', 'pet'])
所有值: dict_values(['Alice', 21, 'dog'])
所有键值对: dict_items([('name', 'Alice'), ('age', 21), ('pet', 'dog')])

8.2.6 检查键是否存在

我们可以使用in关键字来检查字典中是否存在某个键:

# 检查字典中是否存在某个键
has_pet = "pet" in person
print("是否有宠物:", has_pet)
是否有宠物: True

8.2.7 字典推导式

字典推导式是一种快速创建字典的方法,语法与列表推导式类似:

# 字典推导式的语法结构
{key: value for key, value in iterable if condition}

8.2.7.1 示例

  1. 创建水果名称及其长度的字典
fruits = ['apple', 'banana', 'cherry', 'date']
fruit_to_length = {fruit: len(fruit) for fruit in fruits}
print("水果及其长度:", fruit_to_length)
水果及其长度: {'apple': 5, 'banana': 6, 'cherry': 6, 'date': 4}
  1. 创建奇数及其立方的字典
odd_cubes = {x: x**3 for x in range(10) if x % 2 == 1}
print("奇数及其立方:", odd_cubes)
奇数及其立方: {1: 1, 3: 27, 5: 125, 7: 343, 9: 729}

8.2.8 练习题

  1. 创建一个字典,存储你最喜欢的三种食物及其价格,然后:
    • 打印出所有食物及其价格
    • 修改其中一种食物的价格
    • 添加一种新的食物

🌟 要点总结

  1. 字典是存储键值对的无序集合
  2. 通过键访问对应的值
  3. 字典是可变的,可以随时修改、添加或删除
  4. 使用get()方法安全访问字典中的值
  5. 字典推导式可以快速创建字典
  6. 字典的键必须是唯一的,值可以重复

8.3 集合:无序且独特的元素

想象你在参加一个派对,派对上有很多人。每个人都是独特的,不能重复。集合在Python中就是用来存储这种独特元素的工具。

8.3.1 什么是集合?

集合是Python中的一种数据结构,用于存储无序且不重复的元素。集合用花括号 {} 括起来,元素之间用逗号 , 分隔。

# 定义一个集合
fruits = {'apple', 'banana', 'cherry', 'date'}
print("水果集合:", fruits)
水果集合: {'banana', 'date', 'cherry', 'apple'}

8.3.2 集合的特点

  • 无序:集合中的元素没有固定的顺序。
  • 不重复:集合中的每个元素都是唯一的,不能有重复的值。

8.3.3 去重操作

集合的一个常见用途是去重。我们可以使用 set() 函数将列表转换为集合,从而实现去重。

# 定义一个包含重复元素的列表
fruits_list = ['apple', 'banana', 'cherry', 'date', 'apple', 'banana']

# 将列表转换为集合,自动去重
unique_fruits = set(fruits_list)
print("去重后的水果集合:", unique_fruits)
去重后的水果集合: {'date', 'banana', 'cherry', 'apple'}

8.3.4 集合的基本操作

集合支持多种操作,如并集、交集和差集,这些操作的语法非常简单,类似于数学运算。

操作 语法 描述
并集 set1 | set2 返回两个集合的并集
交集 set1 & set2 返回两个集合的交集
差集 set1 - set2 返回两个集合的差集
# 定义两个集合
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}

# 计算两个集合的并集
union_set = set1 | set2
print("并集:", union_set)

# 计算两个集合的交集
intersection_set = set1 & set2
print("交集:", intersection_set)

# 计算两个集合的差集
difference_set = set1 - set2
print("差集:", difference_set)
并集: {1, 2, 3, 4, 5, 6, 7, 8}
交集: {4, 5}
差集: {1, 2, 3}

8.3.5 集合的优点

  • 快速查找:集合的查找速度比列表快得多,适合需要频繁查找的场景。
  • 去重功能:集合自动去重,简化了代码。

8.3.6 实际应用示例

# 假设我们有两个班级的学生名单
class_a = {'小明', '小红', '小华'}
class_b = {'小华', '小李', '小张'}

# 找出两个班级的共同学生(交集)
common_students = class_a & class_b
print("共同学生:", common_students)

# 找出所有学生(并集)
all_students = class_a | class_b
print("所有学生:", all_students)

# 找出只在班级A的学生(差集)
only_class_a = class_a - class_b
print("只在班级A的学生:", only_class_a)
共同学生: {'小华'}
所有学生: {'小李', '小华', '小张', '小红', '小明'}
只在班级A的学生: {'小红', '小明'}

8.3.7 练习题

  1. 创建一个包含你最喜欢的运动的集合,然后:
    • 添加新的运动
    • 删除一种运动
    • 打印所有运动

🌟 要点总结

  1. 集合是无序且不重复的元素集合
  2. 使用花括号 {} 创建集合
  3. 集合支持并集、交集和差集等操作
  4. 集合的查找速度快,适合去重和快速查找
  5. 使用集合可以简化代码,提高效率

8.4 案例研究

接下来是一个简单的练习,你可以通过它巩固对数据结构的理解:

在这个练习中,你需要编写一个程序来管理机器学习模型的训练数据。你需要完成以下任务:

  • 创建一个包含多个样本数据的列表,每个样本包含特征值和标签。
  • 计算并输出所有样本的平均特征值。
  • 找到并输出特征值最大的样本及其标签。
  • 找到并输出特征值最小的样本及其标签。

训练数据表如下:

样本ID 特征值 标签
样本1 0.8 1
样本2 0.6 0
样本3 0.4 0
样本4 0.9 1
样本5 0.7 1
# 创建一个包含多个样本数据的列表
samples = [
    {'id': '样本1', 'feature': 0.8, 'label': 1},
    {'id': '样本2', 'feature': 0.6, 'label': 0},
    {'id': '样本3', 'feature': 0.4, 'label': 0},
    {'id': '样本4', 'feature': 0.9, 'label': 1},
    {'id': '样本5', 'feature': 0.7, 'label': 1}
]

# 计算并输出所有样本的平均特征值
total_feature = 0
for sample in samples:
    total_feature += sample['feature']
average_feature = total_feature / len(samples)
print(f"所有样本的平均特征值是:{average_feature}")

# 找出并输出特征值最大的样本及其标签
highest_feature = samples[0]['feature']
highest_feature_sample = samples[0]['id']
highest_feature_label = samples[0]['label']
for sample in samples:
    if sample['feature'] > highest_feature:
        highest_feature = sample['feature']
        highest_feature_sample = sample['id']
        highest_feature_label = sample['label']
print(f"特征值最大的样本是:{highest_feature_sample},特征值是:{highest_feature},标签是:{highest_feature_label}")

# 找出并输出特征值最小的样本及其标签
lowest_feature = samples[0]['feature']
lowest_feature_sample = samples[0]['id']
lowest_feature_label = samples[0]['label']
for sample in samples:
    if sample['feature'] < lowest_feature:
        lowest_feature = sample['feature']
        lowest_feature_sample = sample['id']
        lowest_feature_label = sample['label']
print(f"特征值最小的样本是:{lowest_feature_sample},特征值是:{lowest_feature},标签是:{lowest_feature_label}")
所有样本的平均特征值是:0.6799999999999999
特征值最大的样本是:样本4,特征值是:0.9,标签是:1
特征值最小的样本是:样本3,特征值是:0.4,标签是:0

💡 数据结构在机器学习中的应用

基本数据结构为机器学习算法的实现提供了基础支持,合理使用它们可以让代码更加清晰和高效。

在机器学习中,不同的数据结构有着不同的应用场景:

  1. 列表(List)
    • 用于存储训练数据集,每个元素可以是样本的特征向量
    • 存储模型的预测结果
    • 记录训练过程中的损失值或准确率
  2. 元组(Tuple)
    • 用于存储不可变的模型参数
    • 表示图像数据的维度(高度、宽度、通道数)
    • 存储数据集的形状信息
  3. 集合(Set)
    • 用于存储唯一的类别标签
    • 去除训练数据中的重复样本
    • 存储词汇表(在自然语言处理中)
  4. 字典(Dict)
    • 存储模型的超参数配置
    • 组织特征名称和对应的特征值
    • 记录训练过程中的各种指标
    • 存储预训练模型的权重