将变量从一个函数传递到另一个函数时如何避免不必要的循环

时间:2017-05-10 20:30:41

标签: python python-3.x

根据要求发布部分实际代码,我的目的是学习和练习构建数独方块的示例编程,大部分代码已被省略,但下面的代码应该是可运行的并且代表我的问题。既然代码已经在这里,我们很高兴地采取改进建议,但主要问题仍然是如何不必要地避免loopin:

from random import shuffle
#for brevity ill omit how i got to this point
sudoku =[6,1,9,3,2,8,5,4,7,2,5,7,6,9,4,3,1,8,4,3,8,7,1,5,2,6,9,5,8,6,1,4,
          3,9,7,2,3,9,1,2,8,7,6,5,4,7,4,2,9,5,6,1,8,3,None,None,None,None,
          None,None,None,None,None,None,None,None,None,None,None,None,None,
          None,None,None,None,None,None,None,None,None,None]

#provides args for list indexing to help satisfy sudoku sub-square rule
sq_pos = [(0, 1, 2, 9, 10, 11, 18, 19, 20),
          (3, 4, 5, 12, 13, 14, 21, 22, 23),
          (6, 7, 8, 15, 16, 17, 24, 25, 26),
          (27, 28, 29, 36, 37, 38, 45, 46, 47),
          (30, 31, 32, 39, 40, 41, 48, 49, 50),
          (33, 34, 35, 42, 43, 44, 51, 52, 53),
          (54, 55, 56, 63, 64, 65, 72, 73, 74),
          (57, 58, 59, 66, 67, 68, 75, 76, 77),
          (60, 61, 62, 69, 70, 71, 78, 79, 80)]

#this function finds allowed numbers for each column
def lastColumnsPossibilities(slist, n_of_square):
    poss_col = []
    print('in lastColumnsPossibilities')
    for j in range(n_of_square*3, 3*n_of_square + 3):
        col = []
        pcol = []
        for i in range(j, j + 46, 9):
            col.append(slist[i])
        for k in range(1,10):                
            if k not in col:
                pcol.append(k)
        poss_col.append(pcol)
    return poss_col

#this function uses allowed numbers output by previous one
def lastSquareFill(slist, n_of_square, ff, fs, ft, 
                   sf, ss, st, tf, ts, tt):
    poss_col = lastColumnsPossibilities(slist, n_of_square)
    plist = poss_col[0]
    shuffle(plist)
    slist[ff] = plist.pop()
    slist[sf] = plist.pop()
    slist[tf] = plist.pop()
    dlist = poss_col[1]
    shuffle(dlist)
    slist[fs] = dlist.pop()
    slist[ss] = dlist.pop()
    slist[ts] = dlist.pop()
    tlist = poss_col[2]
    shuffle(tlist)
    slist[ft] = tlist.pop()
    slist[st] = tlist.pop()
    slist[tt] = tlist.pop()

#this function provides condition according to sudoku rules
def checkRow(slist, rn):
    row = []
    for i in range(rn * 9, rn * 9 + 9):
        row.append(slist[i])
    if len(set(row)) == 9:
        return True
    else:
        return False

#my actual loop is ofc longer, but instead of posting everything i 
#provided list sudoku that is 2/3 filled
def testLoop(slist):
    print('test')
    while (checkRow(slist, 6) != True
           or checkRow(slist, 7) != True
           or checkRow(slist, 8) != True):
        print('loop')
        lastSquareFill(sudoku, 0, *sq_pos[6])
        lastSquareFill(sudoku, 1, *sq_pos[7])
        lastSquareFill(sudoku, 2, *sq_pos[8])

testLoop(sudoku)

我得到的输出是:

loop
in lastColumnsPossibilities
in lastColumnsPossibilities
in lastColumnsPossibilities 
loop
in lastColumnsPossibilities
in lastColumnsPossibilities
in lastColumnsPossibilities   #this repeats over and over

我想要的输出是:

loop
in lastColumnsPossibilities
in lastColumnsPossibilities
in lastColumnsPossibilities 
loop
loop                         #only loop till solution is found

我原来的问题是,现在仍然是如何在不引入新的全局变量的情况下不进行无用的骑行(这是一种不好的做法,我被告知)。作为初学者,我很乐意接受任何其他建议,考虑我的代码和我的问题发布。对不起以前的不好问题,这是我的第一个...

2 个答案:

答案 0 :(得分:1)

通过问题编辑,它确实澄清了手头的问题,所以我相信这就是你所追求的。

我修改了lastSquareFill以取消poss_col取消对它的调用。

def lastSquareFill(slist, n_of_square, poss_col, ff, fs, ft, 
                   sf, ss, st, tf, ts, tt):
    plist = poss_col[0]
    shuffle(plist)
    ...

然后我将调用移到了while循环之外,创建了每个lastColumnsPossibilities的列表,你也可以为每个调用一个变量,但我发现它更清晰。

# Variable for each
lcp0 = lastColumnsPossibilities(sudoku, 0)
lcp1 = lastColumnsPossibilities(sudoku, 1)
...
def testLoop(slist):
    print('test')
    # Create list of each lastColumnsPossibilities
    # range(3) is used to match the 3 calls, but you will likely have 9 for sudoku
    lcp = [lastColumnsPossibilities(sudoku, i) for i in range(3)]
    while (checkRow(slist, 6) != True
           or checkRow(slist, 7) != True
           or checkRow(slist, 8) != True):
        print('loop')
        lastSquareFill(sudoku, 0, lcp[0], *sq_pos[6])
        lastSquareFill(sudoku, 1, lcp[1], *sq_pos[7])
        lastSquareFill(sudoku, 2, lcp[2], *sq_pos[8])

这会产生以下输出

test
in lastColumnsPossibilities
in lastColumnsPossibilities
in lastColumnsPossibilities
loop
loop

如果您希望它首先进入循环以避免在没有检查的情况下进行处理,那么您可以使用dict(列表仍然有效,但dict会更优化)

def lastSquareFill(slist, n_of_square, lcp, ff, fs, ft, 
                   sf, ss, st, tf, ts, tt):


    # if they don't exist create them and add to the dict
    if n_of_square not in lcp:      
        lcp[n_of_square] = lastColumnsPossibilities(slist, n_of_square)

    poss_col = lcp[n_of_square]
    plist = poss_col[0]
    shuffle(plist)
    ...

def testLoop(slist):
    print('test')
    lcp = {} # dict to hold all the lastColumnsPossibilities mapped to the square number
    while (checkRow(slist, 6) != True
           or checkRow(slist, 7) != True
           or checkRow(slist, 8) != True):
        print('loop')
        lastSquareFill(sudoku, 0, lcp, *sq_pos[6])
        lastSquareFill(sudoku, 1, lcp, *sq_pos[7])
        lastSquareFill(sudoku, 2, lcp, *sq_pos[8])

然后给出

test
loop
in lastColumnsPossibilities
in lastColumnsPossibilities
in lastColumnsPossibilities
loop

<强>更新

lastSquareFill中,您需要复制列表[:],以便在弹出值时不会影响原始列表。

# make a copy instead
plist = poss_col[0][:] 
dlist = poss_col[1][:]
tlist = poss_col[2][:]

答案 1 :(得分:0)

很难理解你的代码在做什么,因为很多内容被无用的模糊评论所取代。尽管如此 -

在您的次优&#39;解决方案,您将a作为参数传递给b,这样您就可以在函数中调用a并将其返回值分配给局部变量var。这非常低效,特别是因为您说值a返回不会发生变化。避免全局变量的解决方案是:

def a(list, arg):
    return another_list

def b(_list, arg, a_value, *args):
    # Your code here #
    return _list

def Main(list): 
    while some_function():
        var=a(_list, arg)
        b(_list, arg, var, *args)
        b(_list, arg, var, *args)
        b(_list, arg, var, *args)