为什么应用set()查找列表频次极值元素时结果存在差异
带
key=lst.count的max/min操作 加/不加set()结果差异的原理解析 核心运行规则
max/min配合key参数的并列处理逻辑:遍历可迭代对象时,仅当当前元素的key值严格大于(max场景)/严格小于(min场景)已记录的极值时,才更新当前的极值对象;key值与极值相等时,直接跳过不更新。这意味着当多个元素的key值完全持平时,最终返回的结果一定是整个迭代过程中第一个被碰到的、持有该极值key值的元素。- 提前计算所有元素对应的
lst.count()值:- 字符A:在原列表中出现1次
- 字符B:在原列表中出现3次
- 字符C:在原列表中出现3次
- 字符E:在原列表中出现1次
即所有元素的最高key值为3(B、C并列),最低key值为1(A、E并列),存在两组完全对等的并列场景。
直接传入原列表的执行结果逻辑
直接将原列表lst作为可迭代对象传入时,迭代顺序完全固定为列表的物理存储顺序:A → B → B → B → C → C → C → E
- 执行
max(lst, key=lst.count)时,第一个拿到最高key值3的元素是索引1位置的B,后续遍历到的所有C元素虽然key值同样为3,但因不满足“严格大于当前极值”的条件,不会触发更新,最终返回B。 - 执行
min(lst, key=lst.count)时,第一个拿到最低key值1的元素是索引0位置的A,后续遍历到的E元素虽然key值同样为1,但因不满足“严格小于当前极值”的条件,不会触发更新,最终返回A。
传入set(lst)的执行结果逻辑
这里的核心认知偏差,是多数人默认set(lst)的迭代顺序是“原列表去重后的自然顺序”(即A→B→C→E),但实际上:
- set是典型的无序容器,Python3.7之前的版本完全不保证set的迭代顺序,顺序由元素哈希值、内存布局随机决定;3.7之后的版本虽然将“set保留元素第一次插入的顺序”纳入语言规范,但这个插入顺序和我们预想的“原列表去重顺序”没有必然关联,更不会和自然字母顺序匹配。
- 从给出的运行结果可以反推,在当前运行环境下,
set(lst)的实际迭代顺序为C → B → E → A,完全贴合得到的返回结果:- 执行
max(set(lst), key=lst.count)时,第一个拿到最高key值3的元素是C,后续遍历到的B元素key值同样为3,因不满足严格大于的条件不触发更新,最终返回C。 - 执行
min(set(lst), key=lst.count)时,遍历过程中第一个拿到最低key值1的元素是E,后续遍历到的A元素key值同样为1,因不满足严格小于的条件不触发更新,最终返回E。
- 执行
- 这个结果不具备普适性:只要换一个Python版本、甚至重启同一个Python解释器,
set(lst)的迭代顺序就可能发生变化,对应的max/min返回值也会同步变化——毕竟在key值并列的前提下,谁先被迭代到,谁就是最终的返回结果。
内容的提问来源于stack exchange,提问作者Daniel Hao
相关产品推荐
相关产品推荐

