比较两个点元组列表的更快方法?

时间:2011-06-08 01:06:15

标签: python list-comprehension

我有两个列表(长度可能相同,也可能不同)。在每个列表中,是一系列两个点的元组(基本上是X,Y值)。

我将这两个列表相互比较,找到两个具有相似点值的点。我已经尝试过列表理解技术,但它对列表中的嵌套元组感到困惑,我无法让它工作。

这是最好(最快)的方式吗?我觉得可能有更多的Pythonic方式来做这件事。

说我有两个清单:

pointPairA = [(2,1), (4,8)]
pointPairB = [(3,2), (10,2), (4,2)]

然后是一个用于存储对的空列表和一个仅存储匹配对的容差值

matchedPairs = []
tolerance = 2

然后这个解包元组的循环,比较差异,并将它们添加到matchedPairs列表中以表示匹配。

for pointPairA in pointPairListA:
    for pointPairB in pointPairListB:
        ## Assign the current X,Y values for each pair
        pointPairA_x, pointPairA_y = pointPairA
        pointPairB_x, pointPairB_x = pointPairB

        ## Get the difference of each set of points
        xDiff = abs(pointPairA_x - pointPairB_x)
        yDiff = abs(pointPairA1_y - pointPairB_y)

        if xDiff < tolerance and yDiff < tolerance:
            matchedPairs.append((pointPairA, pointPairB))

这会导致matchesPairs看起来像这样,里面有两个点元组的元组:

[( (2,1), (3,2) ), ( (2,1), (4,2) )]

3 个答案:

答案 0 :(得分:2)

如果这些列表很大,我建议找一个更快的算法......

我首先要通过对中的(x,y)之和对两个对列表进行排序。 (因为两个点只有在它们的总和接近时才能关闭。)

对于第一个列表中的任何一点,这将严重限制您在第二个列表中搜索所需的范围。跟踪第二个列表上的“滑动窗口”,对应于其总和在第一个列表的当前元素总和的2*tolerance范围内的元素。 (实际上,你只需要跟踪滑动窗口的开始......)

假设tolerance相当小,这应该将您的O(n ^ 2)操作转换为O(n log n)。

答案 1 :(得分:2)

这里pointpairA是单个列表,pointpairB将是20k的列表之一

from collections import defaultdict
from itertools import product

pointPairA = [(2,1), (4,8)]
pointPairB = [(3,2), (10,2), (4,2)]
tolerance = 2

dA = defaultdict(list)
tolrange = range(-tolerance, tolerance+1)
for pA, dx, dy in product(pointPairA, tolrange, tolrange):
    dA[pA[0]+dx,pA[1]+dy].append(pA)

# you would have a loop here though the 20k lists
matchedPairs = [(pA, pB) for pB in pointPairB for pA in dA[pB]]  

print matchedPairs

答案 2 :(得分:1)

使用列表理解:

[(pa, pb) for pa in pointPairA for pb in pointPairB \
          if abs(pa[0]-pb[0]) <= tolerance and abs(pa[1]-pb[1]) <= tolerance]

比你的循环快一点:

(for 1 million executions)

>>> (list comprehension).timeit()
2.1963138580322266 s

>>> (your method).timeit()
2.454944133758545 s