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


    一、set去重简单实例

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

    我们知道对于一个列表最简单的去重方法就是直接调用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))

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

    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))

    我看可以看出,实际上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))

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

    三、结论

    set的去重是通过两个函数__hash__和__eq__结合实现的。
    1、当两个变量的哈希值不相同时,就认为这两个变量是不同的
    2、当两个变量哈希值一样时,调用__eq__方法,当返回值为True时认为这两个变量是同一个,应该去除一个。返回FALSE时,不去重

     四、应用场景

     需求

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

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

    请实现员工去重:

    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)])
  • 相关阅读:
    Zookeeper全解析——Paxos作为灵魂(转)
    你真的会开发测试框架?
    使用Hypothesis生成测试数据
    poium测试库之JavaScript API封装原理
    PHP接口自动化测试框架实现
    Web项目如何做单元测试
    如何在Appium中使用AI定位
    我写了个项目,帮你学习HTTP接口测试!
    性能测试浅谈
    Web测试框架SeleniumBase
  • 原文地址:https://www.cnblogs.com/linshuhui/p/9580620.html
Copyright © 2020-2023  润新知