【问题标题】:Arbitrary Dictionary (JSON) to Stricter Tree-like Dictionary (JSON) in PythonPython中的任意字典(JSON)到更严格的树状字典(JSON)
【发布时间】:2013-01-21 22:28:18
【问题描述】:

伙计们,

我有任意字典,其中可能包含任意数量的其他字典和数组的嵌套,例如:

{
    "a": {
        "b": "1",
        "c": [
            {
                "d": "2"
            },
            {
                "d": {
                    "e": "3",
                    "f": "4"
                }
            }
        ]
    }
}

我想把它很好地表示为一棵树,为了做到这一点,我想将它转换为如下结构:

{
    "name": "a",
    "children": [
        {
            "name": "b",
            "value": "1"
        },
        {
            "name": "c",
            "children": [
                {
                    "name": "d",
                    "value": "2"
                },
                {
                    "name": "d",
                    "children": [
                        {
                            "name": "e",
                            "value": "3"
                        },
                        {
                            "name": "f",
                            "value": "4"
                        }
                    ]
                }
            ]
        }
    ]
}

我认为,这样做需要类似地处理子字典和子数组。但是,我很难想出一种方法来进行这种转变。我曾尝试使用递归,也尝试使用包含“名称”、“值”和“孩子”的键/值的节点类,但我很难解析任意深度的输入创建此常规节点/树表示。

这看起来像人们以前做过的事情吗?非常感谢您的意见。

【问题讨论】:

  • 只是想知道,这是一个正在生成的 ExtJS 树吗?
  • 乔恩,感谢您的留言。在您发表评论之前,我没有听说过 ExtJS,现在正在研究它。说实话,我希望使用 d3.js 将输出用于数据可视化 - 我正在处理的示例是 mbostock.github.com/d3/talk/20111018/tree.html
  • 哇 - 太可怕了 - 我也正在使用 d3 做一些事情 - 只需要先完成设计......我只是问,因为它看起来像一个嵌套树的东西,我很久以前使用 ExtJS(但只是模糊地熟悉,我倾向于在 JS 东西爆炸之前尽快将其从我的脑海中剔除 :))

标签: python json recursion tree dictionary


【解决方案1】:

您正确地将其识别为树状数据结构,并且转换它是非常明智的,因为原始表示已被完全破坏。

既然你知道你有一棵树,你需要问自己它的节点是什么。在您的情况下,节点是:

  1. 一片叶子,有一个名字和一个值
  2. 具有名称和子节点的内部节点

问题在于第二种类型有两种不同的表示方式:

  1. 一对("<name>", { "<child1>" : ..., "<child2>" })
  2. 一对("<name>", [{"<child1>" : ... }, { "<child2>": ... }])

您的示例没有显示它,但也许以下也是可能的:

("<name>", [{"<child1>" : ... }, { "<child2>": ..., "<child3>": ... }])

递归确实是解决这个问题的好方法。边缘情况很清楚,它是叶节点。您只需要先检查其他两种情况:

def transform_node(name, val):
    if isinstance(val, list):
        val = ("children", [transform_node(k,v) for x in val for k, v in x.items()])
    elif isinstance(val, dict):
        val = ("children", [transform_node(*kv) for kv in val.items()])
    else:
        val = ("value", val)
    return dict([("name", name), val])

现在你得到:

>>> transform_node("a", 3)
{'name': 'a', 'value': 3}
>>> transform_node("a", { "c1" : 3, "c2" : 4 })
{'name': 'a', 'children': [{'name': 'c2', 'value': 4}, {'name': 'c1', 'value': 3}]}
>>> transform_node("a", [{ "c1" : 3 }, { "c2" : 4, "c3": 5 }])
{'name': 'a', 'children': [{'name': 'c1', 'value': 3}, {'name': 'c3', 'value': 5}, {'name': 'c2', 'value': 4}]}

完美!现在你可以这样做了:

>>> tree = { "a": { "b": 1 }}
>>> transform_node("root", tree)
{'name': 'root', 'children': [{'name': 'a', 'children': [{'name': 'b', 'value': 1}]}]}

当然,如果您希望“a”作为根,那么您可以提取根的第一个子节点。

也就是说,使用类而不是完全无类型的字典将其表示为真实数据类型可能会更好。

【讨论】:

  • 尼克拉斯,谢谢!我很佩服。将其与我们的基本示例进行对比,它运行良好。但是,当针对一些真实数据运行它时,它会出错。在列表分支周围包裹了一个 try/except 之后,我可以看到这个中断的地方是遇到一个不包含 dict 元素而只是字符串(即[“a”,“b”])的数组时。现在工作,看看我是否可以通过为每个数组元素生成一个叶节点来解决这些情况。哇,你在这里真的帮了我很多,我知道我有很多关于 Python 的知识。
  • 所以也有两种不同的方式来表示一个叶子节点。这些数据真的很混乱:)
猜你喜欢
  • 2019-02-03
  • 2013-04-20
  • 1970-01-01
  • 2018-05-31
  • 2018-02-03
  • 2014-11-02
  • 1970-01-01
  • 1970-01-01
  • 2017-03-25
相关资源
最近更新 更多