Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在非常大的列表中配对重复对象_Python - Fatal编程技术网

Python 在非常大的列表中配对重复对象

Python 在非常大的列表中配对重复对象,python,Python,我的程序太慢了。 以下是我需要代码执行的操作。(实际代码如下所示): 想象一下,你有一个非常大(1百万以上)的“人”对象列表。每个人都有“头发颜色”、“身高”、“体重”等属性。每个都有一个isMatched布尔属性 代码所做的是针对列表中的每个person对象:尝试通过属性找到与另一个人的精确匹配。当代码找到两个匹配的person对象时,只需将它们放入一个“pair”对象中。如果没有匹配项,那么我们只需将person对象与None对象配对。这是密码 Deck=collections.deque(

我的程序太慢了。 以下是我需要代码执行的操作。(实际代码如下所示):

想象一下,你有一个非常大(1百万以上)的“人”对象列表。每个人都有“头发颜色”、“身高”、“体重”等属性。每个都有一个isMatched布尔属性

代码所做的是针对列表中的每个person对象:尝试通过属性找到与另一个人的精确匹配。当代码找到两个匹配的person对象时,只需将它们放入一个“pair”对象中。如果没有匹配项,那么我们只需将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万也要花太长的时间。有人知道我如何加快速度吗?

因为您只寻找精确匹配,所以解决方案非常简单

为每个人构建一个属性元组。以下是几种方法:

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

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

d = {}
for person in persons:
   tup = gettuple(person) # use previous code snippets
   d.setdefault(tup,[]).append(person)
…最后,dict d包含所有匹配项的列表。请注意,某些匹配可能包括两人以上,可能是一个奇数,因此您必须选择如何配对,这取决于您。但这将非常快地处理匹配,因为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变大时,它无论如何都会爆炸。”

你真的想要O(n)表示速度,就像我的解决方案一样(扫描列表一次,构建一个散列,再次扫描列表寻找匹配项)


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

因为您只寻找精确匹配,所以解决方案非常简单

为每个人构建一个属性元组。以下是几种方法:

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

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

d = {}
for person in persons:
   tup = gettuple(person) # use previous code snippets
   d.setdefault(tup,[]).append(person)
…最后,dict d包含所有匹配项的列表。请注意,某些匹配可能包括两人以上,可能是一个奇数,因此您必须选择如何配对,这取决于您。但这将非常快地处理匹配,因为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变大时,它无论如何都会爆炸。”

你真的想要O(n)表示速度,就像我的解决方案一样(扫描列表一次,构建一个散列,再次扫描列表寻找匹配项)


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

O(n)
对OP的
O(n^2)
进行了巨大改进。完全正确!如果这东西适合RAM,那么dict就不会被打败。但是,如果这些数据来自数据库,那么在SQL中执行会更快,因为它会跳过检索所有数据的过程……我以为for循环在找到匹配项后就停止了?在每次迭代中,列表变得越来越小?我不是无视你的代码,但我的理解正确吗?从390秒到100k lis