将重复对象配对在一个非常大的列表中

时间:2017-07-08 23:52:24

标签: python

我的程序问题太慢了。 这是我需要我的代码。 (实际代码如下):

想象一下,你有一个非常大(1百万+)的“人”对象列表。每个人都有“hairColor”,“height”,“weight”等属性。每个人都有一个isMatched布尔属性。

代码的作用是对于列表中的每个人对象:尝试通过属性找到与另一个人的完全匹配。当代码找到匹配的两个人对象时,只需将它们放入“对”对象中。如果没有匹配,那么我们只需将person对象与None配对。这是代码

Deck=collections.deque()
Person=[per1,per2,.....per1000000]
while Person:
    personToBeMatched=Person.pop()
    if not personToBeMatched.isMatched:
        match=next(per for per in Person if  per.hairColor==personToBeMatched.hairColor and per.height==personToBeMatched.height, None)
        if match is not None:
            per.isMatched=True
    Deck.append(Pair(match,personToBeMatched))

我最终希望快速做到这个大小为100万的名单,但即使是10万也需要太长时间。有谁知道如何加快速度?

1 个答案:

答案 0 :(得分:4)

由于您只是在寻找完全匹配,因此解决方案非常简单。

对于每个人,构建一个属性元组。以下是一些方法:

person.tup = (person.hairColor, person.height, ...)

keys = "hairColor", "height", .....
tup = (person[k] for k in keys)

现在,由于元组是可以清除的,我们可以将所有内容都放在dict中并使用元组作为键:

d = {}
for person in persons:
   tup = gettuple(person) # use previous code snippets
   d.setdefault(tup,[]).append(person)

...最后,dict d包含所有匹配的列表。请注意,某些匹配可能包含超过2个人,可能包含奇数,因此您必须选择如何配对,这取决于您。但这会很快处理你的匹配,因为dict查找非常快。

这个解决方案更快的原因是它是O(n),即每个人只进行一次dict查找,而dict查找是O(1)。您的解决方案将每条记录与其他所有记录进行比较,因此为O(n ^ 2),这是您真正想要避免的。

另一个解决方案是根据键的元组进行排序,匹配将在排序结果中彼此相邻显示。

编辑:

您的解决方案(即操作数)与大小为n的列表的复杂性:

它从列表中取出一个元素,并将其与所有其他元素进行比较,因此我们最多只进行(n-1)次比较。它在它找到的第一个元素处停止,因此它通常会更少。所以我们可以添加一个软糖因子k = 0.5,并且平均说它在列表的第一个k *(n-1)个元素中找到匹配。

然后它再次在列表上再做一次,这个元素是1个元素(因此是n-2)元素....直到列表用完为止。

所以你得到k *((n-1)+(n-2)+ ... + 2 + 1)操作。

这或多或少是k / 2 * n ^ 2

点是,当你有一个n ^ 2时,k(或1/2)的值并不重要。这就是为什么我们说O(n ^ 2)含义" n ^ 2乘以我们不关心的任何常数,因为当n变大时,无论如何它都会爆炸。&# 34;

你真的希望O(n)获得速度,就像我的解决方案一样(扫描列表一次,构建一个哈希值,再次扫描列表寻找匹配项)。

如果列表很大(即,不适合RAM),那么基于哈希的东西往往会失败,因为哈希映射中的随机访问模式与存储在慢速驱动器上的虚拟内存不兼容。因此,您需要具有磁盘友好访问模式的内容,例如O(n log n)中的合并排序。您可能会使用SQL数据库,因为它们附带内置功能。<​​/ p>

相关问题