Python 练习讲解 · 04 / 25

字典、集合与元组

同一组数据可以用不同容器表达不同需求:计数、去重、保留顺序、固定内容。

要学习的知识点

题目

练习 4:用字典统计整数频次,并按首次出现顺序输出不同整数。

输入:第一行 n,第二行 n 个整数(空格分隔)。

参考程序:ex04.py;空白练习:lx04.py。

完整代码

以下内容与 ex04.py 一致,可对照右侧讲解阅读。

"""练习 4:用字典统计整数频次,并按首次出现顺序输出不同整数。
输入:第一行 n,第二行 n 个整数(空格分隔)。

学习说明:
- split() 把输入行拆成数字文本;for 循环逐个转换为整数并保存到列表。
- tuple(values) 把列表转换为不可修改的元组。
- frequencies 字典保存“整数 -> 出现次数”;用 if/else 判断键是否存在,再更新次数。
- seen 集合检查数字是否见过;unique_in_order 列表按首次出现顺序保存不同数字。
- 最后分别输出频次、不同数字和元组。
"""
n = int(input())
value_texts = input().split()
values = []

for index in range(n):
    value_text = value_texts[index]
    value = int(value_text)
    values.append(value)

values_tuple = tuple(values)

frequencies = {}
seen = set()
unique_in_order = []
for value in values:
    if value in frequencies:
        frequencies[value] = frequencies[value] + 1
    else:
        frequencies[value] = 1

    if value not in seen:
        seen.add(value)
        unique_in_order.append(value)

print("frequencies:")
for value, count in frequencies.items():
    print(value, count)
print("unique:")
for value in unique_in_order:
    print(value)
print("tuple:", values_tuple)

进阶写法

这版与初学版解决同一道题,写法更精炼。先读代码,再看下面的简要说明。

进阶源码文件:ex04_adv.py

"""练习 4 进阶版:用 map、切片、字典 get 和星号解包简化步骤。"""
n = int(input())
values = list(map(int, input().split()))[:n]
values_tuple = tuple(values)

frequencies = {}
seen = set()
unique_in_order = []
for value in values:
    frequencies[value] = frequencies.get(value, 0) + 1
    if value not in seen:
        seen.add(value)
        unique_in_order.append(value)

print("frequencies:")
for value, count in frequencies.items():
    print(value, count)
print("unique:", *unique_in_order)
print("tuple:", values_tuple)

list(map(...)) 先把数字文本转换并保存成列表,[:n] 取前 n 项;dict.get(value, 0) 表示键不存在时先当作 0,再加一;print(..., *unique_in_order) 用星号把列表中的值逐个传给 print。

运行结果

示例输入:

6
4 2 4 1 2 4

程序输出:

frequencies:
4 3
2 2
1 1
unique:
4
2
1
tuple: (4, 2, 4, 1, 2, 4)

逐个认识函数

下面只列出本程序实际用到的写法;先看参数如何传入,再看返回值怎样保存或输出。

函数/写法功能与返回值注意事项
input()读取一行并返回字符串。本题读取元素数量和数字文本行。
str.split()按空白拆分字符串,返回文本列表。循环中再逐个转换为整数。
int(text)把整数文本转换为整数。每次只转换一个数字。
range(n)产生 n 个下标:0 到 n-1。本题用它依次读取 n 个输入项。
list.append(value)在列表末尾追加一个值;返回 None。将转换后的整数保存到 values。
tuple(values)从可迭代对象创建元组。元组的元素序列不能被修改。
set() / set.add(value)创建集合 / 向集合添加元素。集合用于判断数字是否见过,不用来保持输出顺序。
dict.items()提供字典中的键值对供循环遍历。可写成 for key, value in frequencies.items()。
print(...)输出对象;返回 None。不同数字逐行输出,避免星号解包。

三种容器的分工

类型适合做什么本题中的变量
list 列表有顺序、可修改、允许重复。values 保存输入;unique_in_order 按发现顺序保存不重复数。
dict 字典用键查值;键唯一。现代 Python 字典保持插入顺序。frequencies 将数字映射到出现次数。
set 集合元素唯一,可快速判断成员关系;不承诺适合展示的顺序。seen 只回答“这个数以前见过吗”。
tuple 元组有顺序、允许重复,但创建后不能增删改元素。values_tuple 保存输入序列的固定版本。

输入与字典计数

输入行通过 split() 拆成文本,再用循环逐项 int() 转成整数。更新频次时先判断 value 是否已经是 frequencies 的键:如果有就加一;如果没有,就把次数设成一。

if value in frequencies:
    frequencies[value] = frequencies[value] + 1
else:
    frequencies[value] = 1

这和 get() 的快捷写法效果相同,但把“第一次出现”和“再次出现”分开写出来了。

算法流程:数一次、记一次

  1. 每读到一个 value,字典里的计数在旧值基础上加 1。
  2. 用 value not in seen 判断首次出现。not 是逻辑“非”。
  3. 首次出现就同时加入集合和顺序列表。集合负责查重,列表负责保序,两者不能互相替代。
  4. 遍历字典显示计数,再显示唯一列表和元组。

如果直接把集合打印出来,顺序不适合作为题目答案的一部分。要保序去重,就像本程序一样同时使用 set 和 list。

代码如何运行

  1. 先按左侧题目给出的格式输入数据;程序通过 input() 读取,并在需要时转换数据类型。
  2. 程序自上而下执行语句;遇到条件、循环或函数调用时,按照右侧算法说明更新变量和处理数据。
  3. 最后由 print() 输出计算结果。可将左侧示例输入与输出逐项对照。

先自己跟踪一组小数据,记录循环前后变量的值;这比只看最终答案更容易理解程序。

自己动手试一试

测试所有数都相同、所有数都不同;观察字典顺序与集合用途的区别。

先在 lx04.py 中独立完成,再运行参考程序比较结果。修改程序时一次只改一个条件或步骤。