提高Python嵌套for循环的性能

时间:2012-12-07 00:44:22

标签: python performance loops

我有两组数字,每组都在我的Python脚本的列表中。对于第一个列表中的每个数字,我需要查看第二个列表中的任何数字是否大于它。我只需要n2大于n1的次数。 (例如,如果numset1[7,2]numset2[6,9],我只需要3) 现在我正在这样做 - 通过每个n1并检查每个n2是否大于它:

possibilities = [(n1<n2) for n1 in numset1 for n2 in numset2]
numPossibilities = sum(possibilities)

目前这是我脚本中最慢的部分,特别是在处理较大的数据集时(numset1和numset2包含数千个数字)。我确信有一些方法可以提高效率,我只是不确定如何。

3 个答案:

答案 0 :(得分:3)

排序numset2,然后迭代numset1,但在numset2上使用二进制搜索,例如使用bisect模块:http://docs.python.org/2/library/bisect.html

import bisect
# your code here
numset2.sort()
L = len(numset2)
numPossibilities = sum([bisect.bisect_right(numset2,n1) < L for n1 in numset1])

另请注意,您的原始代码无法计算您在第二句中要求的内容 - 对于numset1中的每个元素,它会在numset2中总计多少元素大于这个元素,而不是是否有一个符合标准的元素。

要匹配原始代码,请执行以下操作:

numPossibilities = sum([L - bisect.bisect_right(numset2,n1) for n1 in numset1])

答案 1 :(得分:2)

您的问题是,您必须对(n1, n2)的每个组合进行迭代,并且有len(numset1) * len(numset2)个组合,当numset1numset2仅公平时,这些组合会非常大大。

换句话说,算法的运行时间是O(n ^ 2)(如果len(numset1)大约等于len(numset2)。让我们的运行时间更快。: - )

如果我们对列表进行排序,这将变得更容易。我们要对numset1numset2进行排序。

>>> numset1.sort()
>>> numset2.sort()

现在,比较numset1的最小元素(称之为n1)和numset2的最小元素(称之为n2)。如果n1较小,则我们知道len(numset2)中的numset2元素大于n2。如果numset1较小,我们知道>>> n1_idx, n2_idx, accumulator = 0, 0, 0 >>> while n1_idx < len(numset1) and n2_idx < len(numset2): if numset1[n1_idx] < numset2[n2_idx]: accumulator += len(numset2) - n2_idx n1_idx += 1 else: n2_idx += 1 中的任何元素都不会小于它。

现在,我们不想实际删除列表开头的元素,因为这是对Python列表的O(n)操作。因此,让我们跟踪每个列表中的位置并进行迭代。

accumulator

在这个操作结束时,我们花了O(nlog(n))时间排序列表和O(n)时间进行迭代,所以我们的整体运行时复杂度是O(nlog(n))。 / p>

那个,而(n1, n2)的{​​{1}}对的数量为n1 < n2

答案 2 :(得分:0)

这应该是一个非常有效的实现:

def get_possibilities(numset1, numset2):
    sortset1 = sorted(numset1)
    sortset2 = sorted(numset2)
    total = 0
    i2 = 0
    for i1, n1 in enumerate(sortset1, 1):
        while sortset2[i2] <= n1:
            i2 += 1
            if i2 >= len(sortset2):
                # reached end of i2, so just return total now
                return total
            # current from sortset2 is greater than from sortset1 so far
            total += i1
    # all remaining elements of sortset2 greater than all elements of sortset1
    total += (len(sortset2) - i2 - 1) * len(sortset1)
    return total

这只迭代每个集合一次,它通过在运行之前对集合进行排序来完成。这允许一些改进的逻辑,因为如果索引sortset2的{​​{1}}中的元素大于索引i2的{​​{1}}元素,那么它也大于所有元素在早期指数的sortset1中。