【问题标题】:Python ordered list search versus searching sets for list of objectsPython有序列表搜索与对象列表搜索集
【发布时间】:2019-01-14 13:34:18
【问题描述】:

我有两个对象列表。我们将列表称为 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

我强烈怀疑有更快的方法来实现这一点。名单很长。每个最多 100 000 个对象。所以这是我代码中的一大瓶颈。

我查看了这个答案Fastest way to search a list in python,它表明套装效果更好。不过,我对此有点困惑:

  • “删除重复项”加速有多大意义?我不希望我的列表中有很多重复项。

  • 当我按照我的方式定义 eq 时,集合可以删除重复项并正确散列吗?

  • 这与预先排序列表和使用二分搜索之类的方法相比如何?一个集合是无序的...

那么这里最好的方法是什么?请在答案中提供实施指南。

【问题讨论】:

  • 我从第一个代码块中得到了一些语法错误。 def MyObj: 是指class MyObj: 吗? continue,你的意思是pass吗?
  • 是的对不起现在编辑
  • 您不能基于字符串进行散列。两个相等的对象必须具有相同的哈希值。

标签: python list search set


【解决方案1】:

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 的实例由它们的一个常量self.integer 字段分类。然后您可以尝试比较较小的子列表。这至少会通过聚类减少搜索空间。

【讨论】:

  • 只是乍一看评论。您可能应该将 TL;DR 部分放在最上面,因为这基本上就是它的目的。
  • @scharette 点。我通常喜欢将 TL;DR 放在文章底部,以鼓励读者阅读整篇文章(尤其是在三段或更少的情况下)。但是这篇文章足够长,将它移到顶部是值得的。谢谢!
  • 是的,你可能已经知道了,TL;DR 代表 “too long, don't read” 所以把它放在底部鼓励人们阅读您的帖子似乎适得其反。如果您想鼓励他们阅读,请不要包含一个(即使它与此处相关)。不管怎样,你的帖子质量真的很好。干得好。
  • @EdwardMinnix 感谢您的回答。我不知道 hash 方法,所以感谢您解释这一点,这清除了我怀疑的问题,但不知道为什么。我现在很清楚为什么散列不起作用。我没有想到你提到的排序算法的问题。我想我假设“相似”单词的第一个字母总是相同的,所以我可以对此进行“部分”排序,但考虑到我的数据来源,虽然很可能是这种情况,但这甚至不是一定是真的。
  • @EdwardMinnix 我已经在整数上实现了分桶。我形成字典,其中整数是键,值是具有该整数的对象的子列表。我不认为这会提供巨大的加速,因为如果整数不匹配,fuzzywuzzy 计算无论如何都会被跳过,但我错了,它总体上提供了约 55% 的加速(包括分桶成本)。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-06
  • 2015-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多