• python set()去重的底层原理


    大家早好、午好、晚好吖 ❤ ~欢迎光临本文章

    如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码

    一、set去重简单实例

    ls = [1,2,3,1,2]
    print(set(ls))
    
    • 1
    • 2

    我们知道对于一个列表最简单的去重方法就是直接调用set函数,利用集合元素的唯一性,就可以做到去重。

    但是,这个底层原理究竟是什么样的却一直半解。

    且看下面剖析

    二、重新set实现机制

    class Foo:
        def __init__(self,name,count):
            self.name = name
            self.count = count
        def __hash__(self):
            print("%s调用了哈希方法"%self.name)
            return hash(id(self))
        def __eq__(self, other):
            print("%s调用了eq方法")
            if self.__dict__ == other.__dict__:
                return True
            else:return False
    f1 = Foo('f1',1)
    f2 = Foo('f2',2)
    f3 = Foo('f3',3)
    ls = [f1,f2,f3]
    print(set(ls))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    从上面可以看出,set方法就是去调用hash方法,然后根据哈希值一不一样就行去重判断,但是事实就是样吗?

    且看下面程序。

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:702813599
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    class Foo:
        def __init__(self,name,count):
            self.name = name
            self.count = count
        def __hash__(self):
            print("%s调用了哈希方法"%self.name)
            return hash(self.count)
        def __eq__(self, other):
            print("%s调用了eq方法"%self.name)
            return self.__dict__ == other.__dict__
    
    f1 = Foo('f1',1)
    f2 = Foo('f2',1)
    f3 = Foo('f3',3)
    ls = [f1,f2,f3]
    print(set(ls))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    我看可以看出,实际上f1,f3的哈希值是相等的,但是set并没有这么简单就判断f1,f3是重复的

    而是进一步通过eq方法判断这两个值是否相等,只有相等时才会认为这两个之间实际上是同一个。

    为了验证上面的说法,我们来看看下面的代码。

    f1 = Foo('f1',1)
    f2 = Foo('f1',1)
    f3 = Foo('f3',3)
    ls = [f1,f2,f3]
    print(set(ls))
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以看出去重后,只有两个元素,所以上面说法得证。

    三、结论

    set的去重是通过两个函数__hash__和__eq__结合实现的。

    1、当两个变量的哈希值不相同时,就认为这两个变量是不同的

    2、当两个变量哈希值一样时,调用__eq__方法,当返回值为True时认为这两个变量是同一个,应该去除一个。返回FALSE时,不去重

    四、应用场景

    需求

    有一个公司,现有100个员工,由于数据库不完善,使用时间比较长,里面有很多重复数据需要清除。

    具体需求如下:

    每个员工的属性有:姓名,性别,年龄,部门。

    由于年龄和部门都会发生变化,所以现在认为只要两个员工之间姓名和性别一样,就认为是同一个人。

    请实现员工去重:

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:702813599
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    class Staff:
        def __init__(self,name,gender,age,department):
            self.name = name
            self.gender = gender
            self.age  = age
            self.department = department
        def __hash__(self):
            return hash(self.name+self.gender)
        def __eq__(self, other):
            return True
    ls = ['zs','ls','ww','zq']
    gender_list = ['man','femal']
    staff_list = []
    for i in range(100):
        staff_list.append(Staff(ls[i%4],gender_list[i%2],i,'class'))
    print(set(staff_list))
    print([(i.name,i.gender) for i in set(staff_list)])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    尾语

    好了,今天的分享就差不多到这里了!

    对下一篇大家想看什么,可在评论区留言哦!看到我会更新哒(ง •_•)ง

    喜欢就关注一下博主,或点赞收藏评论一下我的文章叭!!!

    最后,宣传一下呀~👇👇👇 更多源码、资料、素材、解答、交流 皆点击下方名片获取呀👇👇👇

  • 相关阅读:
    Linux64Bit下安装MySQL5.6-不能修改root密码
    Git管理工具教程01
    JVM复习
    学会如何写一篇符合搜索引擎排名要求的高质量SEO文章
    lua vm 一: attempt to yield across a C-call boundary 的原因分析
    计算机毕业设计Java幼儿校园通系统的设计与实现(系统+程序+mysql数据库+Lw文档)
    通常我们可以从哪里找到真实靠谱的考研真题?
    LCHub 6 月低代码平台排行榜发布
    spring boot 测试用例
    【TcaplusDB知识库】TcaplusDB技术支持介绍
  • 原文地址:https://blog.csdn.net/weixin_62853513/article/details/133810537