Python排序列表搜索与对象列表搜索集

时间:2018-08-07 12:44:37

标签: python list search set

我有两个对象列表。让我们将列表称为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 时,设置可以删除重复项并正确地进行哈希处理吗?

  • 与将列表预排序并使用诸如二进制搜索之类的东西相比,这将如何?一组无序...

那么最好的方法是什么?请在答案中也提供实施准则。

1 个答案:

答案 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距离的一定范围内确定的。然后bookhook彼此相似(距离= 1),但是距离{2的hack会更接近hook。那么在这种情况下,您如何定义一个好的模糊搜索排序算法?

要尝试的一件事是使用某种形式的分组/存储桶操作,例如类型为Dict[int, List[MyObj]]的字典,其中MyObj的实例通过其一个常量{{ 1}}字段。然后,您可以尝试比较较小的子列表。这样至少可以通过聚类减少搜索空间。