【问题标题】:Find all the possible paths in csv file在 csv 文件中查找所有可能的路径
【发布时间】:2017-01-08 06:48:12
【问题描述】:

我有一个格式如下的 csv 文件:

header1,header2,header3,header4
1,4,2,5
1,4,0,5
0,4,2,5

我的问题的相关信息仅在第 1 列和第 3 列中。我试图在此 csv 文件中找到所有可能的路径,如果它们在同一行中,则两个值连接(在定向路径中) .比如上面的数据中:

1 is connected to 2
1 is connected to 0
0 is connected to 2

那么所有可能的路径是:

[1,2]
[1,0,2]
[0,2]

借助在线资源(特别是this),我已经能够找到指定起始节点和结束节点的所有路径。以下是我的代码:

import csv  
def main():
   inputFile = "file_directory"
   a =[]
   with open(inputFile) as csvfile:
      reader = csv.reader(csvfile)
      next(reader)
      for line in reader:
         a.append([line[0], line[2]])
   # This will print all the paths starting with 1 and ending with 2
   print(str(getAllSimplePaths('1', '2', a)))


def getAllSimplePaths(originNode, targetNode, a):
      return helpGetAllSimplePaths(targetNode,
                         [originNode],
                         set(originNode),
                         a,
                         list())


def helpGetAllSimplePaths(targetNode, currentPath, usedNodes, a, answerPaths):
  lastNode = currentPath[-1]
  if lastNode == targetNode:
    answerPaths.append(list(currentPath))
  else:
    for elem in a:
      if elem[0] == lastNode:
        if elem[1] not in usedNodes:
          currentPath.append(elem[1])
          usedNodes.add(elem[1])
          helpGetAllSimplePaths(targetNode,currentPath,usedNodes,a,answerPaths)
          usedNodes.remove(elem[1])
          currentPath.pop()
  return answerPaths               


if __name__ == '__main__':
   main()

当我运行它时,我正确地得到了以下结果:

[['1', '2'], ['1', '0', '2']]

但是,我真正想做的是能够遍历 csv 文件第二列中的所有元素,并找到每个元素的所有可能路径。我已经为此工作了好几天,但我想不出办法来做到这一点。我的 csv 文件有大约 2000 行。任何帮助/建议将不胜感激!谢谢!

更新:额外信息

csv 文件中的每一行已经是两个元素之间的路径。因此,我拥有的路径数将等于我在 csv 文件中拥有的行数。现在,从我的问题示例中的第一行开始,1 连接到 2,因此 ['1','2'] 是一条路径。对于每一行,我想通过查看同一行第三列 (elem2) 来查找第一列中的元素 (elem1) 所连接的内容,然后在 csv 文件中的所有行中搜索第一列中的 elem2。如果它存在于某行的第一列,则 elem2 必须连接到同一行第三列 (elem3) 中的相应元素。在这种情况下,我们的路径是 [elem1,elem2,elem3]。同样对于 elem3 我将不得不查看所有行以查看它是否存在于第一列中。如果它不存在,那么我就完成了第一条路径。接下来我继续第二条路径。

上述示例的所需输出如下所示:

[['1','2'], ['1', '0', '2'], ['0', '2'], ['1','0']]

我正在使用 Python 3.5.1。

【问题讨论】:

  • 是否有可能出现循环,例如是否存在1 连接到00 连接到1 的情况?如果是,那么在这种情况下所需的输出是什么?
  • 是的,有可能出现循环。但是,上面的代码旨在检测到这一点,并且不允许发生循​​环。例如,如果 1 连接到 2 并且 2 连接到 1 程序将只输出 [['1', '2']] 假定 1 是开始节点,2 是结束节点。
  • 首先我建议您修复问题中代码的缩进。另外,“每个元素的所有可能路径”是什么意思——从什么到什么的路径?
  • 这可能是一个不成熟的(不考虑您的代码)和幼稚的问题,但在我看来,存储位置信息可能是有价值的。我会检查你的代码,但现在,使用你的例子,说 col1:1 连接到 col3:2,col1:1 连接到 col3:0,col1:0 连接到 col3:2 是否有价值,因此,col1:1 连接到 col3:2,col1:1 连接到 col3:0 和 col3:2,col1:0 连接到 col3:2?无论这是否增加了价值,我是否在您的示例中正确解释了可能的路径?
  • @martineau 对,我已经更新了。谢谢!

标签: python list python-3.x csv path


【解决方案1】:

已编辑

这是一个我进行了更多优化的版本。在你对一个非常大的 csv 文件使用它之前,我建议你删除它所做的部分/大部分打印——这不会影响最终结果。

import csv
from pprint import pprint, pformat

def main():
    inputFile = "paths.csv"
    with open(inputFile, newline='') as csvfile:
       reader = csv.reader(csvfile)
       next(reader)
       a = [[row[0], row[2]] for row in reader]
    print('a:\n', pformat(a))

    # construct an adjacency *dictionary*
    nodeToNodes = {}
    for src, dst in a:
        nodeToNodes.setdefault(src, []).append(dst)
    print('\nnodeToNodes:\n', pformat(nodeToNodes))

    print('\ngathering results:')
    all_paths = []
    for src, dst in a:
        print('  {} <-> {}'.format(src, dst))
        more_paths = getAllSimplePaths(dst, [src], {src}, nodeToNodes, [])
        print('    {}'.format(pformat(more_paths)))
        all_paths.extend(more_paths)

    print('\nall paths: {}'.format(pformat(all_paths)))

def getAllSimplePaths(targetNode, currentPath, usedNodes, nodeToNodes, answerPaths):
    lastNode = currentPath[-1]
    if lastNode == targetNode:
        answerPaths.append(currentPath[:])
    elif lastNode in nodeToNodes:
        for neighbor in nodeToNodes[lastNode]:
            if neighbor not in usedNodes:
                currentPath.append(neighbor)
                usedNodes.add(neighbor)
                getAllSimplePaths(targetNode, currentPath, usedNodes, nodeToNodes,
                                  answerPaths)
                usedNodes.remove(neighbor)
                currentPath.pop()

    return answerPaths

if __name__ == '__main__':
   main()

输出:

a:
 [['1', '2'], ['1', '0'], ['0', '2']]

nodeToNodes:
 {'0': ['2'], '1': ['2', '0']}

gathering results:
  1 <-> 2
    [['1', '2'], ['1', '0', '2']]
  1 <-> 0
    [['1', '0']]
  0 <-> 2
    [['0', '2']]

all paths: [['1', '2'], ['1', '0', '2'], ['1', '0'], ['0', '2']]

【讨论】:

  • 谢谢!这适用于小型 csv 文件。我尝试将它应用于具有 2000 行并且无限运行的 csv 文件。有没有办法更有效地做到这一点?
  • 不客气。我注意到,由于在main() 中的最后一个for 循环中进行了打印,getAllSimplePaths() 函数被两次 调用用于同一对节点。我已将其从答案中删除,这将使其更快。不知道你的 2000 行 csv 文件需要多少钱,不过......
  • 我进行了一些优化以加快速度。如果您想提供 2000 行的 csv 文件(通过下载链接),我会看看是否还有什么可以做的——假设它仍然太慢。
猜你喜欢
  • 2017-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 2023-03-03
  • 2018-02-19
相关资源
最近更新 更多