在python

时间:2016-10-19 22:55:05

标签: python json tree

修改 正如@Alfe在评论中建议的那样,在这种情况下的确切问题是以下代码无法处理具有相同值的节点。那么,如何在不改变节点值的情况下获得预期的输出?

我正在执行以下代码,以便从JSON数据生成树:

from __future__ import print_function
import json
import sys

# Tree in JSON format
s = '{"Harry": {"children": ["Bill", {"Jane": {"children": [{"Diane": {"children": ["Mary"]}}, "Mark"]}}]}}'

# Convert JSON tree to a Python dict
data = json.loads(s)

# Extract tree edges from the dict
edges = []

def get_edges(treedict, parent=None):
    name = next(iter(treedict.keys()))
    if parent is not None:
        edges.append((parent, name))
    for item in treedict[name]["children"]:
        if isinstance(item, dict):
            get_edges(item, parent=name)
        else:
            edges.append((name, item))

get_edges(data)

# Dump edge list in Graphviz DOT format
print('strict digraph tree {')
for row in edges:
    print('    {0} -> {1};'.format(*row))
print('}')

终端使用的命令:python filename.py | dot -Tpng -otree.png

使用String输入,如上面的代码所示,输出为: enter image description here

但是如果我用整数输入JSON数据:

s = '{"92": {"children": [{"87": {"children": [87, 96]}}, {"96": {"children": [90, 105]}}]}}'

我得到以下输出:(这是错误的!)

enter image description here

预期产量: enter image description here

我在这里做错了什么?如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

根据问题中的编辑进行编辑:

考虑到你的输出,它给了我:

92 -> 87;
87 -> 87;
87 -> 96;
92 -> 96;
96 -> 90;
96 -> 105;

它显示"87"87相同,因为您使用.format() print将{值}插入字符串中而不依赖于维护引号" 。例如:

>>> '{}'.format(1)
'1'
>>> '{}'.format('1')
'1'

为了解决这个问题,你可以这样做:

for parent, child in edges:
    parent = '"{}"'.format(parent)  if isinstance(parent, str) else parent
    child = '"{}"'.format(child)  if isinstance(child, str) else child
    print('    {0} -> {1};'.format(parent, child))

打印:

"92" -> "87";
"87" -> 87;
"87" -> 96;
"92" -> "96";
"96" -> 90;
"96" -> 105;

答案 1 :(得分:1)

你的问题是使用统一字符串和数字的工具dot,因此它将名称相同的节点视为相同(意思是:只是一个)。您需要为每个节点提供唯一的ID。然后可以调整图形输出以反映不同节点中的相同名称。

示例:

echo '
strict digraph tree {
  92 -> 87 -> "87a";
  "87a" [label="87"];
  87 -> "96a";
  "96a" [label="96"];
  92 -> 96 -> 90;
  96 -> 105 }
' | dot -Tpng -otree.png

这将产生您想要的输出(带有有向边)。

我相应地更改了您的代码以实现此调整:

#!/usr/bin/env python2

from __future__ import print_function
import json
import sys

# Tree in JSON format
s = '{"92": {"children": [{"87": {"children": [87, 96]}}, {"96": {"children": [90, 105]}}]}}'

# Convert JSON tree to a Python dict
data = json.loads(s)

# Extract tree edges from the dict
edges = []

def x(node):
    return '%s%s' % (node, type(node))

def get_edges(treedict, parent=None):
    name = next(iter(treedict.keys()))
    if parent is not None:
        edges.append((x(parent), x(name), parent, name))
    for item in treedict[name]["children"]:
        if isinstance(item, dict):
            get_edges(item, parent=name)
        else:
            edges.append((x(name), x(item), name, item))

get_edges(data)

# Dump edge list in Graphviz DOT format
print('strict digraph tree {')
for row in edges:
    print('    "{0}" -> "{1}"; "{0}" [label="{2}"]; "{1}" [label="{3}"];'.format(*row))
print('}')

这使用特殊的内部节点ID,它们组合了节点名称及其类型(str / unicode或int),并为每个隐藏此内部ID的节点设置标签。