背景
在做数据清洗的时候,想要实现一个程序,去除数据集里面相同的图片。那么我很快就想到了用set()去对数据进行一个过滤,那么怎么实现呢?
我的实现思路
class Img:
def __init__(self, img, file_name):
self.img = img
self.file = file_name
def __eq__(self, other):
print("进入相等判断")
if self.img.shape != other.img.shape:
# 如果图片shape都不一样 那肯定不一样
return False
return np.array_equal(self.img, other.img)
def __str__(self):
return "-- "+str(self.file)+" --"
def __hash__(self):
a, b, c = self.img.shape
self.hash = hash(a)+hash(b)+hash(c)
return hash(a)+hash(b)+hash(c)
def demo1():
# set 是先用 __hash__ 如果hash相等 那么再用__eq__比较
array1 = np.random.rand(*(1, 2, 3)) # 生成0到1之间的随机浮点数
array2 = np.random.randint(0, 10, size=(1,2,3)) # 生成0到9之间的随机整数
# 用两个数组来模拟图片
img1 = Img(array1, "1")
img2 = Img(array2, "2")
print(img1.img.all() == img2.img.all())
fina = set()
fina.add(img1)
fina.add(img2)
for i in fina:
print(i)
print(img1.hash == img2.hash)
首先,构建一个Img类,里面有图片的np数组和图片的文件名。然后,再写一个测试函数demo1。在测试函数里面,我用两个shape一样的随机数组来代替两张长,宽,颜色通道一样但内容不一样的图片。最后运行demo1,输出如下。
False
进入相等判断
-- 1 --
-- 2 --
True
# 这个结果说明了 两个对象的hash值是一样的
# set调用了元素类的__eq__方法进行比较发现这两个元素是不一样的
# 上面的现象好像说明了
# set是先用元素类的__hash__方法进行去重
# 如果元素的hash值相同再用元素的__eq__方法去重
为了保险我们再写个demo2测试函数。
def demo2():
# set 是先用 __hash__ 如果hash相等 那么再用__eq__比较
array1 = np.random.rand(*(1, 2, 3)) # 生成0到1之间的随机浮点数
array2 = np.random.randint(0, 9, size=(3,2,3)) # 生成0到9之间的随机整数
print(array2.all() == array1.all())
# 用两个数组来模拟图片
img1 = Img(array1, "1")
img2 = Img(array2, "2")
print(img1.img.all() == img2.img.all())
fina = set()
fina.add(img1)
fina.add(img2)
for i in fina:
print(i)
print(img1.hash == img2.hash)
输出结果为以下,这就更说明了,set的去重逻辑,如果集合元素里面的hash值不一样的话,那么这两个元素就不一样,否则进行__eq__方法的比较。
False
-- 2 --
-- 1 --
False
set()集合去重底层逻辑
set的去重是通过两个函数__hash__和__eq__结合实现的。当两个变量的哈希值不相同时,就认为这两个变量是不同的;当两个变量哈希值一样时,调用__eq__方法,当返回值为True时认为这两个变量是同一个,应该去除一个。返回FALSE时,不去重。