【问题标题】:Python list of lists specific path combinations or permutations列表特定路径组合或排列的 Python 列表
【发布时间】:2017-08-24 22:30:01
【问题描述】:

我有一个列表列表,我正在寻找类似于组合或排列的内容,但有些条件可能会导致良好的“路径”或“死角”。如果是“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]

这是一条好路径,有许多好路径和许多死角。例如,另一个好的路径是 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,但是对于一个稍大的列表的 itertools 所有组合,比如说 10 个数据节点突然变成了数百万个路径。然后我必须 set() 它们来消除选择。回到我的绘图板上。

【问题讨论】:

  • 您似乎希望我们为您编写一些代码。虽然许多用户愿意为陷入困境的程序员编写代码,但他们通常只在发布者已经尝试自己解决问题时才提供帮助。展示这项工作的一个好方法是包含您迄今为止编写的代码(形成minimal reproducible example)、示例输入(如果有的话)、预期输出和您实际获得的输出(输出、回溯、等等。)。您提供的详细信息越多,您可能收到的答案就越多。检查tourHow to Ask
  • 专门解决您的最后一个问题:有很多方法可以做到这一点,但在您发布尝试之前,不太可能有人会帮助您。这就像学习任何类型的数学:首先你用困难的方式做它,然后他们教你捷径......以你知道的方式尝试你的手,然后有人可能会告诉你一个更快的技巧。
  • 明白。在询问捷径之前,我将在今晚晚些时候先发布我一直在尝试的漫长道路。

标签: python list loops indexing itertools


【解决方案1】:

一遍又一遍地阅读问题的文本,我发现了两种用于找到正确答案的规则变体,并将在此处提供它们两种,而无需询问哪一个是 OP 想到的问题。

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

第一步:将所有矩阵值组成一个具有唯一值的平面集合

Step2:创建该集合的所有可能排列

让我们用代码证明这个变体即使在一个非常大的矩阵上也能工作:

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, 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)}

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

【讨论】:

    猜你喜欢
    • 2014-08-08
    • 1970-01-01
    • 2013-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多