Python去重时,为什么要先考虑顺序和可哈希性
把一组数据里的重复项去掉,看起来只需要调用一个方法,但在实际开发中,还要回答两个问题:结果是否需要保留原来的顺序,数据本身能否放进集合或作为字典的键。把这两个条件说明白,才能选到合适的处理方式。
集合适合表达“有哪些不同的值”。对于由整数或字符串组成的列表,转换为集合可以得到唯一值,也便于后续判断某个元素是否存在。不过,集合不承诺保留列表中的输入顺序。即使某次打印结果看上去刚好有序,也不应把这种表现当成业务规则。如果结果需要直接展示给用户,就应该提前确定展示顺序。
当需求是保留第一次出现的位置时,可以利用字典键的唯一性。现代 Python 的字典会保留插入顺序,重复写入已有的键不会把它移动到最后。因此,可以从原始序列建立字典,再取出键作为列表。输入顺序是甲、乙、甲、丙时,得到的顺序就是甲、乙、丙。这里保留的是第一次遇到该值的位置,而不是最后一次。
集合和字典都要求相关元素可哈希。整数、字符串以及元素都可哈希的元组通常可以使用;列表和字典本身则不能直接作为集合成员或字典键。因此,面对一个由字典组成的用户列表,不能简单地把整个列表转换成集合。更合适的做法,是先选定代表业务身份的字段,例如用户编号,再依据这个字段判断是否重复。
身份字段也需要定义清楚。如果两个记录的编号相同,但名称不同,是保留第一条、保留最后一条,还是报告数据冲突,这属于业务规则,去重工具无法代替开发者决定。保留第一条可以使用一个已见编号集合,按输入顺序逐条扫描,只有第一次出现的编号才加入结果。保留最后一条则需要进一步说明最终顺序如何安排,避免只更新内容却误以为位置也会同步改变。
还有一个容易忽略的细节:Python 中,True 和整数 1 比较相等,哈希值也相同,放入集合时会被视为同一个键。如果业务需要区分布尔值与整数,仅靠默认的集合去重就不够,需要把类型也纳入身份规则。类似地,字符串大小写是否敏感、编号前后的空格是否有效,也应由输入规范明确规定。
对很小的不可哈希数据,也可以逐个检查元素是否已经出现在结果列表中。这种方法容易理解,还能保留首次出现的顺序,但随着数据量增长,反复扫描结果列表的开销会增大。是否值得换成基于键的方式,要结合数据规模与比较规则判断。
写去重逻辑前,先用重复值、空输入、顺序变化和身份冲突几个例子确认预期。只要顺序、身份和保留策略三件事有了明确答案,代码通常会很短,结果也更容易解释。
- 点赞
- 收藏
- 关注作者
评论(0)