在python

时间:2018-03-21 12:19:35

标签: python for-loop nested-loops

当一个嵌套for循环的范围达到外部for循环的当前迭代时,如何避免多个嵌套for循环?例如,请考虑以下代码: 该程序从列表arr返回一个三元组,arr[i] - arr[j] = arr[j] - arr[k] = di<j<k

d =3
arr = [1, 2, 4, 5, 7, 8, 10]
list1 = []

for biggest in range(0, len(arr)):
    for bigger in range(0, biggest):
        for big in range(0, bigger):
            if abs(arr[big] - arr[bigger]) == d and abs(arr[bigger] - arr[biggest]) == d:
                list1.append([arr[big], arr[bigger], arr[biggest]])
print(list1))

使用多个嵌套循环还有其他选择吗?

4 个答案:

答案 0 :(得分:3)

您可以用以下内容替换三个循环:

from itertools import combinations

for big, bigger, biggest in combinations(range(0, len(arr)), 3):

您可以将所有代码替换为:

print([t for t in combinations(arr, 3)
       if t[2] - t[1] == t[1] - t[0] == d])

答案 1 :(得分:2)

您可以使用the combinations function from itertools。您的代码将变为:

from itertools import combinations

d = 3
arr = [1, 2, 4, 5, 7, 8, 10]
list1 = []
for big, bigger, biggest in combinations(arr, 3):
    if abs(big - bigger) == d and abs(bigger - biggest) == d:
        list1.append([big, bigger, biggest])

print(list1)

它提供与您的代码相同的打印输出(在您删除最后一行的无关右括号后):

[[1, 4, 7], [2, 5, 8], [4, 7, 10]]

请注意,我将变量bigbiggerbiggest的含义更改为数组值而不是其索引。使用值和避免索引更加诡计多端,更容易理解。

你也可以在列表理解中做到这一点,看起来略有不同,避免临时列表,以及可能的速度增加。

from itertools import combinations

d = 3
arr = [1, 2, 4, 5, 7, 8, 10]
print([[big, bigger, biggest]
        for big, bigger, biggest in combinations(arr, 3)
        if abs(big - bigger) == d and abs(bigger - biggest) == d
    ])

答案 2 :(得分:0)

虽然之前的答案是pythonic, 如果您关心搜索算法的实现,可以通过实现二进制搜索算法在O(N^2logN)之间找到k,从而将算法的复杂性从j+1降低到lst 1}}以及满足d - abs(lst[j] - lst[k]) == 0的{​​{1}}的长度。

d = 3
lst = [1, 2, 4, 5, 7, 8, 10]


def bsearch(lst, left, right, j):
    while left < right:
        k = (left + right) // 2

        diff = d - abs(lst[j] - lst[k])

        if diff == 0:
            return k
        if diff > 0:
            left = k + 1
        else:
            right = k

    return None


l, result = len(lst), []
for i in range(l):
    for j in range(i + 1, l):
        diff = d - abs(lst[i] - lst[j])

        if diff != 0: continue
        k = bsearch(lst, j + 1, l, j)

        if not k: continue
        result.append((lst[i], lst[j], lst[k]))

print(result)

[(1, 4, 7), (2, 5, 8), (4, 7, 10)]

答案 3 :(得分:0)

我发现更好的方法!避免嵌套循环。

arr = [1,2,3,4,5,6,7,8,9]
d = 3
list1 = arr
list2 = []
for each in (0,len(list1)):
    if list1[each] + d in arr and list1[each] + 2*d in arr:
         list2.append([list1[each], list1[each]+d, list1[each]+2*d])
print(list2)