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

时间:2009-05-10 01:34:34

标签: python graph

我正在用Python重写数据驱动的遗留应用程序。其中一个主表被称为“图表”,并且看起来似乎是有向图,所以我正在探索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_wfc_im123并转到节点10130.

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

  • 只有一个选择,所以转到节点10300。

  • “wfc1”在字符串中,因此请选择acs_wfc_ebe_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”,由于未使用的关键字而引发异常

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

    • COS
    • acs,hrc
    • acs,wfc1,f606w
    • acs,wfc1,f550m
    • acs,wfc1,f555w
  • 验证是否可以到达所有节点并且没有循环。

我可以调整Alex的前两个解决方案,但我不知道如何在最后两个方面做到这一点。

2 个答案:

答案 0 :(得分:2)

绝对不适合通用图形库(如果节点中有多个有意义的单词在输入字符串中,那么你应该怎么做 - 这是一个错误吗? - 或者如果没有那么做对于节点,没有默认值,就像您提供的示例中的节点30一样)。只需将表作为dict从节点写入元组(默认的东西,从单词到特定的东西),其中每个东西都是一个元组(目标,单词添加)(并使用None表示特殊的“单词添加”) “clear)。例如:

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

现在处理这个表和输入逗号分隔的字符串很简单,这要归功于set操作 - 例如:

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

答案 1 :(得分:0)

添加答案以响应......中新编辑的进一步要求:我仍然不会选择通用库。对于“所有节点都可以到达并且没有循环”,只需根据集合(忽略触发关键字)进行推理应该:(再次未经测试的代码,但即使存在一些拼写错误,也可以提供一般大纲):

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"

对于“合法字符串”,您需要一些其他代码,但我不能为您编写,因为我还不知道是什么使字符串合法或以其他方式......!