从 csv 数据为折叠菜单创建树结构

Create tree structure from csv data for collapse menu

from collections import defaultdict
import pandas as pd
    df = pd.DataFrame(data)
    d = defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: defaultdict(list))))

    for row in df.itertuples():
        d[row[1]][row[2]][row[3]][row[4]].append(row[5])
    d = json.dumps(d)
    d = json.loads(d)

我有这段代码可以将一些 csv 数据读取为数据帧。我找到了一种使用 defaultdict 创建树状结构的方法,然后循环遍历 df 并填充它。 数据将始终具有相同的深度 分析仪:模式:子模式:文件名:信号

结果如下所示:

{
  "Analyzer1": {
    "Mode1": { "SubMode1": { "filename2": ["Signal1"] } },
    "Mode2": {
      "SubMode2": {
        "filename1": [
          "Signal2",
          "Signal3"
        ]
      }
    },
    "Mode3": {
      "SubMode1": {
        "filename1": ["Signal2"]
      },
      "SubMode3": {
        "filename1": ["Signal3"]
      }
    }
  },
  "Analyzer2": {
    "Mode1": {
      "SubMode4": {
        "filename1": ["Signal2"]
      }
    }
  }
}

这很好,但我有义务对最终结果做一些更改,因为这棵树将与反应包一起使用以显示可折叠菜单(反应复选框树:https://www.npmjs.com/package/react-checkbox-tree

该包使用类似的结构,不同之处在于每个级别都有额外的属性,并且它的子级(如果有的话)在一个列表中。这是我想要实现的输出。

[
  {
    "label": "Analyzer1",
    "value": "analyzer1",
    "children": [
      {
        "label": "Mode1",
        "value": "analyzer1/mode1",
        "children": [
          {
            "label": "SubMode1",
            "value": "analyzer1/mode1/submode1",
            "children": [
              {
                "label": "Filename2",
                "value": "analyzer1/mode1/submode1/filename2",
                "children": [
                  {
                    "label": "Signal1",
                    "value": "analyzer1/mode1/submode1/filename2/signal1"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "label": "Mode2",
        "value": "analyzer1/mode2",
        "children": [
          {
            "label": "SubMode2",
            "value": "analyzer1/mode2/submode2",
            "children": [
              {
                "label": "Filename1",
                "value": "analyzer1/mode2/submode2/filename1",
                "children": [
                  {
                    "label": "Signal2",
                    "value": "analyzer1/mode2/submode2/filename1/signal2"
                  },
                  {
                    "label": "Signal3",
                    "value": "analyzer1/mode2/submode2/filename1/signal3"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "label": "Mode3",
        "value": "analyzer1/mode3",
        "children": [
          {
            "label": "SubMode1",
            "value": "analyzer1/mode3/submode1",
            "children": [ 
              {
                "label": "Filename1",
                "value": "analyzer1/mode3/submode1/filename1",
                "children": [
                  {
                    "label": "Signal2",
                    "value": "analyzer1/mode3/submode1/filename1/signal2"
                  }
                ]
              }
            ]
          },
          {
            "label": "SubMode3",
            "value": "analyzer1/mode3/submode3",
            "children": [ 
              {
                "label": "Filename1",
                "value": "analyzer1/mode3/submode3/filename1",
                "children": [
                  {
                    "label": "Signal3",
                    "value": "analyzer1/mode3/submode3/filename1/signal3"
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "label": "Analyzer2",
    "value": "analyzer2",
    "children": [
      {
        "label": "Mode1",
        "value": "analyzer2/mode1",
        "children": [
          {
            "label": "SubMode4",
            "value": "analyzer2/mode1/submode4",
            "children": [
              {
                "label": "Filename1",
                "value": "analyzer2/mode1/submode4/filename1",
                "children": [
                  {
                    "label": "Signal2",
                    "value": "analyzer2/mode1/submode4/filename1/signal2"
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
]

我尝试了以下方法,但它不完整,我找不到将子节点添加到父节点的方法。

def adjust(d, res, parent, children, path):
        for k, v in d.items():
            if(not isinstance(v, list)):
                path = path + k.lower() + '/'
                parent['value'] = k.lower()
                parent['label'] = k
                adjust(v, res, parent['children'][0], path)
            else:
                parent['children'] = []
            res.append(parent)
adjust(d, [], {}, [], '')

任何建议或指示将不胜感激,我不是很擅长做递归。

你的递归函数不应该有那么多参数。让它自主构建其子树,只需要路径作为来自调用者的额外信息。并使其 functional,以便它 returns 它处理的子树的结果。这样调用者就可以将结果注入到它自己的 children 属性中。

这是它的工作原理:

def maketree(d, path=""):
    if isinstance(d, list):
        return [{ 
            "label": k,
            "value": path + k.lower()
        } for k in d]
    else:
        return [{
            "label": k,
            "value": path + k.lower(),
            "children": maketree(v, path + k.lower() + "/")
        } for k, v in d.items()]

称其为:

tree = maketree(d)