我有两个对象列表。让我们将列表称为a和b。对象(出于我们的意图和目的)定义如下:
class MyObj:
def __init__(self, string: str, integer: int):
self.string = string
self.integer = integer
def __eq__(self, other):
if self.integer == other.integer:
pass
else:
return False
if fuzz.ratio(self.string, other.string) > 90: # fuzzywuzzy library checks if strings are "similar enough"
return True
else:
return False
现在我要实现的是检查列表a中的哪些对象“在”列表b中(与列表b中的某些对象相比,对==返回true)。
目前,我正按如下所述遍历它们:
for obj in a:
for other_obj in b:
if a == b:
<do something>
break
我强烈怀疑有一个更快的方法来实现这一目标。列表很长。每个对象多达10万个对象。因此,这是我代码中的一大瓶颈。
我查看了这个答案Fastest way to search a list in python,它表明集合的工作效果更好。我对此有些困惑:
“删除重复项”加速有多重要?我不希望列表中有很多重复项。
当我按照自己的方式定义 eq 时,设置可以删除重复项并正确地进行哈希处理吗?
那么最好的方法是什么?请在答案中也提供实施准则。
答案 0 :(得分:3)
TL; DR ,当使用模糊比较技术时,如果没有某种归一化方法,就很难进行集合和排序。您可以尝试在尽量减少搜索空间方面保持明智,但应注意保持一致。
如果一个类定义了__eq__
而不是__hash__
,则它是不可哈希的。
例如,考虑以下课程
class Name:
def __init__(self, first, last):
self.first = first
self.last = last
def __repr__(self):
return f'{self.first} {self.last}'
def __eq__(self, other):
return (self.first == other.first) and (self.last == other.last)
现在,如果您要尝试使用这些元素创建一个集合
>>> {Name('Neil', 'Stackoverflow-user')}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'Name'
因此,对于Name
,您只需定义一个__hash__
方法。但是,在您的情况下,这比较困难,因为您具有模糊等式语义。我能想到的解决此问题的唯一方法是拥有一个标准化函数,您可以证明它是一致的,并使用标准化字符串而不是实际字符串作为哈希的一部分。以Floats as dictionary keys为例,需要进行规范化才能使用浮点数之类的“模糊”类型作为键。
对于排序和二进制搜索,由于您是模糊搜索,因此仍然需要小心诸如二进制搜索之类的内容。例如,假设您说相等是由Levenshtein距离的一定范围内确定的。然后book
和hook
彼此相似(距离= 1),但是距离{2的hack
会更接近hook
。那么在这种情况下,您如何定义一个好的模糊搜索排序算法?
要尝试的一件事是使用某种形式的分组/存储桶操作,例如类型为Dict[int, List[MyObj]]
的字典,其中MyObj
的实例通过其一个常量{{ 1}}字段。然后,您可以尝试比较较小的子列表。这样至少可以通过聚类减少搜索空间。