对于我的Python问题,图形库(如NetworkX)是正确的解决方案吗?

对于我的Python问题,图形库(如NetworkX)是正确的解决方案吗?,python,graph,Python,Graph,我正在用Python重写一个数据驱动的遗留应用程序。其中一个主表被称为“graph table”,看起来确实是一个有向图,因此我正在研究NetworkX包,以了解将其用于图形表操作是否有意义,并将其真正实现为一个图,而不是一组复杂的数组 然而,我开始怀疑我们使用这个表的方式是否不适合实际的图形操作库。NetworkX的大部分功能似乎都是以某种方式描述图形本身,确定两个节点之间的最短距离等。这些都与我的申请无关 我希望如果我能描述一下这里的实际使用情况,有人能建议我是否遗漏了一些东西——我以前从未

我正在用Python重写一个数据驱动的遗留应用程序。其中一个主表被称为“graph table”,看起来确实是一个有向图,因此我正在研究NetworkX包,以了解将其用于图形表操作是否有意义,并将其真正实现为一个图,而不是一组复杂的数组

然而,我开始怀疑我们使用这个表的方式是否不适合实际的图形操作库。NetworkX的大部分功能似乎都是以某种方式描述图形本身,确定两个节点之间的最短距离等。这些都与我的申请无关

我希望如果我能描述一下这里的实际使用情况,有人能建议我是否遗漏了一些东西——我以前从未真正使用过图形,所以这是很有可能的——或者我是否应该探索其他数据结构。(如果是,你有什么建议?)

我们使用该表主要是将用户提供的关键字字符串转换为组件的有序列表。这构成了95%的用例;其他5%是“给定部分关键字字符串,提供所有可能的补全”和“生成所有可能的合法关键字字符串”。哦,并验证图形是否存在畸形

以下是该表的编辑摘录。栏目包括:

关键字innode outnode组件

acs 1 20 clear
default 1 100 clear
noota 20 30 clear
default 20 30 hst_ota
ota 20 30 hst_ota
acs 30 10000 clear
cos 30 11000 clear
sbc 10000 10199 clear
hrc 10000 10150 clear
wfc1 10000 10100 clear
default 10100 10101 clear
default 10101 10130 acs_wfc_im123
f606w 10130 10140 acs_f606w
f550m 10130 10140 acs_f550m
f555w 10130 10140 acs_f555w
default 10140 10300 clear
wfc1 10300 10310 acs_wfc_ebe_win12f
default 10310 10320 acs_wfc_ccd1
给定关键字字符串“acs、wfc1、f555w”和该表,遍历逻辑为:

  • 从节点1开始;“acs”在字符串中,因此转到节点20

  • 节点20的所有关键字都不在字符串中,因此选择默认值,选择hst_ota,然后转到节点30

  • “acs”在字符串中,因此转到节点10000

  • “wfc1”在字符串中,因此转到节点10100

  • 只有一个选择;转到节点10101

  • 只有一个选择,所以选择acs\U wfc\U im123并转到节点10130

  • 字符串中有“f555w”,因此选择acs_f555w并转到节点10140

  • 只有一个选择,因此转到节点10300

  • “wfc1”在字符串中,因此选择acs\u wfc\u ebe\u win12f并转到节点10310

  • 只有一个选择,所以选择acs_wfc_ccd1并转到节点10320——它不存在,所以我们完成了

因此,组件的最终列表是

hst_ota
acs_wfc_im123
acs_f555w
acs_wfc_ebe_win12f
acs_wfc_ccd1
我可以从这个表的innodes和outnodes生成一个图,但我一辈子都无法弄清楚如何在关键字信息中进行构建,以确定在面临多种可能性时做出何种选择

更新以添加其他用例的示例:

  • 给定字符串“acs”,返回(“hrc”、“wfc1”)作为下一个可能的合法选择

  • 给定字符串“acs,wfc1,foo”,由于未使用的关键字引发异常

  • 返回所有可能的合法字符串:

    • 因为
    • acs,hrc
    • acs,wfc1,f606w
    • acs,wfc1,F550米
    • acs,wfc1,f555w
  • 验证是否可以访问所有节点,以及是否没有循环


我可以调整Alex的解决方案来解决前两个问题,但我不知道如何解决后两个问题

绝对不适用于通用图形库(如果输入字符串中有多个节点中有意义的单词,则您应该执行的操作——这是错误吗?——或者如果没有,且节点没有默认值,则您应该执行的操作,如您提供的示例中的节点30)。只需将表作为dict-from-node-to-tuple(默认内容,dict-from-word-to-specific内容)写入,其中每个内容都是一个tuple(destination,word-to-add)(对于特殊的“word-to-add”
clear
,使用None)。例如:

tab = {1: (100, None), {'acs': (20, None)}),
       20: ((30, 'hst_ota'), {'ota': (30, 'hst_ota'), 'noota': (30, None)}),
       30: ((None, None), {'acs': (10000,None), 'cos':(11000,None)}),
       etc etc
现在,由于集合操作,处理此表和输入逗号分隔字符串很容易,例如:


添加一个答案,以响应新编辑的进一步要求…:我仍然不会选择通用库。对于“可以到达所有节点,并且没有循环”,简单地按照集合进行推理(忽略触发关键字)应该可以做到:(同样是未测试的代码,但即使有一些输入错误,一般大纲也应该有帮助):


对于“合法字符串”,您将需要一些其他代码,但我不能为您编写它,因为我还不明白是什么使字符串合法或不合法

谢谢亚历克斯!这对遍历用例非常有帮助。不过,我不确定是否还有其他情况-请参阅上面的更新。特别是我想知道图形库是否适用于验证案例?我终于有机会在本周再次参与这个项目,意识到我从未接受过你非常有用的答案!再次感谢。
def f(icss):
  kws = set(icss.split(','))
  N = 1
  while N in tab:
    stuff, others = tab[N]
    found = kws & set(others)
    if found:
      # maybe error if len(found) > 1 ?
      stuff = others[found.pop()]
    N, word_to_add = stuff
    if word_to_add is not None:
      print word_to_add
def add_descendants(someset, node):
  "auxiliary function: add all descendants of node to someset"
  stuff, others = tab[node]
  othernode, _ = stuff
  if othernode is not None:
    someset.add(othernode)
  for othernode, _ in others.values():
    if othernode is not None:
      someset.add(othernode)

def islegal():
  "Return bool, message (bool is True for OK tab, False if not OK)"
  # make set of all nodes ever mentioned in the table
  all_nodes = set()
  for node in tab:
    all_nodes.add(node)
    add_desendants(all_nodes, node)

  # check for loops and connectivity
  previously_seen = set()
  currently_seen = set([1])
  while currently_seen:
    node = currently_seen.pop()
    if node in previously_seen:
      return False, "loop involving node %s" % node
    previously_seen.add(node)
    add_descendants(currently_seen, node)

  unreachable = all_nodes - currently_seen
  if unreachable:
    return False, "%d unreachable nodes: %s" % (len(unreachable), unreachable)
  else:
    terminal = currently_seen - set(tab)
    if terminal:
      return True, "%d terminal nodes: %s" % (len(terminal), terminal)
    return True, "Everything hunky-dory"