Python IndentationError - 如何重构?

时间:2012-09-26 00:05:07

标签: python nested-loops

我正在为编程练习做一个Project Euler问题,以便自我教学。我非常清楚如何以数学方式解决问题,以及如何以编程方式完成。

但是,我必须提出一些疯狂的代码才能做到这一点; 100个嵌套循环和Python搞笑地引发了这个错误,并且可能正确地提出了100个级别的缩进:

IndentationError: too many levels of indentation



tally = 0
ceiling = 100
for integer_1 in range(0, 100, 1):
    for integer_2 in range(0, 100 - integer_1, 2):
        for integer_3 in range(0, 100 - integer_1 - integer_2, 3):
            for integer_4 ....
                for integer_5 ....
                    etc.
                        etc.
                            all the way to integer_100

我已经通过谷歌寻找解决方案,但这个问题非常罕见,几乎没有关于这个主题的文献,我只能找到这个其他堆栈溢出问题(Python IndentationError: too many levels of indentation),我找不到它有用的我的问题。

我的问题是 - 有没有办法采取我的解决方案并找到一些解决方法或以一种有效的方式重构它?我真的很难过。

修改

感谢nneonneo的回答,我能够解决这个问题。我的代码仅供将来参考,以寻找正确重构代码的方法。

from time import time
t = time()
count_rec_dict = {}

# for finding ways to sum to 100
def count_rec(cursum, level):
    global count_rec_dict

    # 99 is the last integer that we could be using,
    # so prevent the algorithm from going further. 
    if level == 99:
        if cursum == 100:
            return 1
        else:
            return 0

    res = 0

    for i in xrange(0, 101-cursum, level+1):

        # fetch branch value from the dictionary
        if (cursum+i, level+1) in count_rec_dict:
            res += count_rec_dict[(cursum+i, level+1)]

        # add branch value to the dictionary
        else:
            count_rec_dict[(cursum+i, level+1)] = count_rec(cursum+i, level+1)
            res += count_rec_dict[(cursum+i, level+1)]        

    return res}

print count_rec(0, 0)
print time() - t

在我的计算机上以惊人的0.041秒运行。哇!!!!!我今天学到了一些新东西!

4 个答案:

答案 0 :(得分:5)

递归解决方案应该做得很好,但我确信对于不需要这种操作的问题有一个完全不同的解决方案。

def count_rec(cursum, level):
    if level == 100:
        return 1
    res = 0
    for i in xrange(0, 100-cursum, level+1):
        res += count_rec(cursum+i, level+1)
    return res

print count_rec(0, 0)

有趣的是,如果你 memoize 这个功能,它实际上会有一个合理的运行时间(例如动态编程的强大功能)。玩得开心!

答案 1 :(得分:1)

避免缩进错误的一种方法是将循环放在单独的函数中,每个函数只嵌套一层深度。

或者,您可以使用递归来反复调用函数,每次都使用较小的范围和较高的嵌套级别。

话虽这么说,无论你如何编码,你的算法都会有一个不可能长的运行时间。你需要一个更好的算法: - )

答案 2 :(得分:1)

要完全使用您的算法(将每个下一个数字限制为可能适合所需总和的数字),您确实需要递归 - 但真正的强力方法可以是单行:

sum(sum(i) == 100 for i in itertools.product(xrange(100), repeat=100))

当然,这比你的算法的真正重构要慢一些(事实上,正如评论中提到的那样,事实证明它是难以处理的。)

答案 3 :(得分:0)

最有效的解决方案是基于算术携带的思想。 您有最大值和步骤列表, 以及当前值列表。每次要更新这100个变量时,都要执行以下操作:

inc_index = -1
currentvalue[inc_index] += stepval[inc_index]
# I use >= rather than > here to replicate range()s behaviour that range(0,100) generates numbers from 0 to 99.
while currentvalue[inc_index] >= maxval[inc_index]:
    currentvalue[inc_index] = 0
    inc_index -= 1
    currentvalue[inc_index] += stepval[inc_index]
# now regenerate maxes for all subordinate indices
while inc_index < -1:
    maxval[inc_index + 1] = 100 - sum (currentvalue[:inc_index])
    inc_index += 1

当引发IndexError时,你已经完成了循环(用完'数字'来进行。)