Python列表特定路径组合或排列

时间:2017-03-30 20:03:26

标签: python list loops indexing itertools

我有一个列表列表,我正在寻找类似于组合或排列的东西,但有些条件可能导致良好的“Path”或“Dead_End”。如果是“Dead_End”,它应该索引到列表中的下一个选项。 例如:

AList = [[1, 2, 3],
         [2, 0, 3],
         [3, 1, 0],
         [1, 0, 2]]

N = 0
Index = 0
#AList[N][Index]=1,  AList[2][2]=0

我想从值AList [N] [Index]开始,它在开始时为[0] [0]因此等于1并将其分配给N.在N被赋值为1之后,我们永远不会去回到那个List和Path = [1]。

然后我会有AList [N] [Index],这是AList [1] [0]并且等于2.将它分配给N. Path.append(N)我会有Path = [1,2] ]

AList [N] [Index]接下来等于3,N = 3,Path将变为[1,2,3]

现在AList [N] [Index]等于1.这将是一个Dead_Path并不是一个好的解决方案,因为1已经在Path中,我们无法再回到它。所以我想索引到列表中的下一个选项。 Index = Index + 1.这将导致AList [N] [Index] = 0. Path = [1,2,3,0]

这是一条很好的路径,有许多好的路径和许多Dead_Ends。例如,另一个好的Path将是Path = [1,0,2,3]。

这是一个多嵌套的IF,For,While循环场景还是有一个itertools函数来测试所有的Paths和Dead_Ends?并且列表列表可能更复杂并且不均匀以创建更多Dead_Ends,例如:

BList = [[1, 4, 3],
         [2, 0, 3, 4],
         [3, 4, 0],
         [1, 2],
         [3, 2, 1, 0]]

编辑: 我无法处理所有Dead_Ends。所有的循环和索引让我感到困惑,所以我认为最好的解决方案是我使用itertools并列出所有路径组合,并允许重新访问上一个节点。然后我将使用set()函数来消除重新访问节点的列表。最后,我留下了Perfect_Paths每次点击一次。我不知道这是否是最快/最干净的,但它确实有效。代码如下:

Perfect_Path = list()
i = 0 

All_Paths = list(itertools.product(*Alist))

for i in range(len(All_Paths)):
    if len(set(All_Paths[i])) == len(Alist):  #filter out paths that revisited a node, which means it would have same number repeated in list
        Perfect_Path.append(All_Paths[i])

print ("The perfect paths are ", Perfect_Path)

编辑:我上面的代码适用于一个小的Alist,但是为了稍微大一些列表迭代所有组合,比如说10个数据节点突然变成数百万个路径。然后我必须设置()它们以消除选择。回到我的绘图板。

1 个答案:

答案 0 :(得分:1)

一遍又一遍地阅读问题的文本,我发现了两种规则的变体,用于找到正确的答案,并且在这里提供两种规则,而不会询问哪一个是OP想到的问题。

让我们从简单的开始吧。通过矩阵元素的路径可以从一个元素跳转到任何其他元素,并且路径的唯一限制是允许的路径中没有相同的值。这使得通过矩阵的值找到所有路径变得非常容易,如下所示:

步骤1:从具有唯一值的平面集中取出所有矩阵值

步骤2:创建此集合的所有可能排列

让我们用代码演示这个变体甚至可以在一个非常大的矩阵上工作:

theMatrix = [[1, 1, 3, 2, 1, 3, 3, 3, 2, 1, 1, 3],
             [1, 2, 1],
             [2, 3, 3, 1, 3, 3, 2, 1, 1, 1, 3, 3, 1, 3, 3],
             [3, 1, 3, 1, 2],
             [2, 3, 3, 1, 3, 3, 2, 1, 1, 1, 3],
             [1, 2],
             [1, 2, 1],
             [2, 3, 3, 1, 3, 3, 1, 1, 3, 3, 1, 3, 3],
             [3, 1, 3, 1, 2],
             [2, 3, 3, 1, 3, 3, 2, 1, 1, 1, 3],
             [1, 2],
             [2, 3, 3, 1, 3, 3, 1, 1, 3, 3, 1, 3, 3],
             [3, 1, 3, 1, 2],
             [2, 3, 3, 1, 3, 3, 2, 1, 1, 1, 3],
             [3, 2, 1, 3, 1]]
setOnlyDifferentMatrixValues = set()
for row in range(len(theMatrix)):
    for column in range(len(theMatrix[row])):
        setOnlyDifferentMatrixValues.add(theMatrix[row][column])
from itertools import permutations
allPossiblePaths = permutations(setOnlyDifferentMatrixValues)
print(list(allPossiblePaths))

上面的代码输出:

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

现在是具有更多代码行的更复杂的变体。代码是必要的,因为那里有更多限制,路径只能通过邻居的矩阵元素(水平,垂直和对角线)。在这种情况下,并非所有路径都具有相同的长度和相同的元素:

def getAllValidPathsFrom(myMatrix): 
# def getDictRepresentationOf(myMatrix):
    dctOfMatrix = {}
    for row in range(len(myMatrix)):
        for column in range(len(myMatrix[row])):
            currPoint = (column, row)
            dctOfMatrix[currPoint] = myMatrix[row][column]

    lstIndicesOfAllMatrixPoints = list(dctOfMatrix.keys())
    setAllPossiblePaths = set()
    from itertools import permutations
    permutationsIndicesOfAllMatrixPoints = permutations(lstIndicesOfAllMatrixPoints)
    cutBranchAt = ()
    sizeOfCutBranch = 0
    for pathCandidate in permutationsIndicesOfAllMatrixPoints: 
        # print(pathCandidate, type(pathCandidate))
        if sizeOfCutBranch > 0:
            # print( "sizeOfCutBranch > 0", cutBranchAt )
            cutBranchAt = tuple(cutBranchAt)
            while cutBranchAt == pathCandidate[0:sizeOfCutBranch]:
                try:
                    pathCandidate = next(permutationsIndicesOfAllMatrixPoints)
                except:
                    break
        lstPossiblePath = []
        prevIndexTuple = pathCandidate[0]
        lstPossiblePath.append(prevIndexTuple)
        for currIndexTuple in pathCandidate[1:]:
            if (abs(currIndexTuple[0]-prevIndexTuple[0]) > 1) or (abs(currIndexTuple[1]-prevIndexTuple[1]) > 1) :
                sizeOfCutBranch = len(lstPossiblePath)+1
                cutBranchAt = tuple(lstPossiblePath+[currIndexTuple])
                break # current path indices not allowed in path (no jumps)
            else:
                if dctOfMatrix[currIndexTuple] in [ dctOfMatrix[index] for index in lstPossiblePath ] : 
                    sizeOfCutBranch = len(lstPossiblePath)+1
                    cutBranchAt = tuple(lstPossiblePath+[currIndexTuple])
                    break # only values different from all previous are allowed 
                else:
                    sizeOfCutBranch = 0
                    cutBranchAt = ()
                    lstPossiblePath.append(currIndexTuple)
                    prevIndexTuple = currIndexTuple
        if len(lstPossiblePath) > 1 and tuple(lstPossiblePath) not in setAllPossiblePaths: 
            setAllPossiblePaths.add(tuple(lstPossiblePath))

    return setAllPossiblePaths, dctOfMatrix
#:def getAllValidSkiingPathsFrom

theMatrix = [[3, 1, 3],
             [1, 1],
             [1, 2, 1, 3]]

lstAllPossiblePaths, dctOfMatrix = getAllValidPathsFrom(theMatrix)
setDifferentPossiblePaths = set(lstAllPossiblePaths)
setTpl = set()
for item in setDifferentPossiblePaths:
    lstTpl = []
    for element in item:
        lstTpl.append(dctOfMatrix[element])
    setTpl.add(tuple(lstTpl))
print(setTpl)

上面的代码在一个小矩阵上运行,因为大的矩阵会在计算上杀死它。由于小矩阵中值的特殊排列,因此可以在此证明,由于构建路径的限制性规则较多,因此不会生成所有排列。让我们比较变体1的输出和答案的变体2:

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

{(1, 2), (1, 3), (2, 1, 3), (3, 1), (2, 1), (3, 1, 2)}

因为在第二个变体中,路径必须经过相邻的矩阵元素,并不存在最长路径的所有排列,并且还包括较短的路径。