You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将点表示法键的对象转换为适配treeselect的树形嵌套JSON

将点表示法键的JS对象转换为适配jquery.treeselect.js的树形结构

需求说明

需要把键采用点表示法的JavaScript对象,转换为包含id、title、has_children、level、value、children字段的层级嵌套结构,用于适配jquery.treeselect.js插件。

示例输入

const obj = {
  "project1.foo.a": "value",
  "project1.foo.b": "value",
  "project1.bar": "value",
  "project2.foo.a": "value",
  "project2.foo.b": "value",
  "project2.foo.c": "value",
  "project2.foo.bar": "value"
};

当前问题

使用lodash实现的unflatten函数仅能还原扁平化对象,但无法递归生成符合插件要求的、包含指定字段的children嵌套结构:

const unflatten = (flattedObject) => {
  let result = {};
  _.keys(flattedObject).forEach(function (key) {    
    _.set(result, key, flattedObject[key]);     
  })
  return result;
}
console.log(unflatten(obj));

实现方案

下面的代码会先构建节点映射,再递归生成符合要求的树形结构:

function convertToTreeselectStructure(flatObj) {
  // 节点映射表,用于快速查找和创建节点
  const nodeMap = new Map();
  const rootNodes = [];

  // 遍历所有键值对,拆分路径并构建节点
  Object.entries(flatObj).forEach(([key, value]) => {
    const pathSegments = key.split('.');
    let parentNode = null;

    pathSegments.forEach((segment, index) => {
      const nodeId = pathSegments.slice(0, index + 1).join('.');
      let node = nodeMap.get(nodeId);

      if (!node) {
        // 创建新节点
        node = {
          id: nodeId,
          title: segment,
          has_children: index !== pathSegments.length - 1, // 非最后一段则有子节点
          level: index,
          value: index === pathSegments.length - 1 ? value : undefined, // 仅叶子节点赋值
          children: []
        };
        nodeMap.set(nodeId, node);

        // 关联父节点或加入根节点列表
        if (index === 0) {
          rootNodes.push(node);
        } else {
          parentNode.children.push(node);
        }
      }

      parentNode = node;
    });
  });

  return rootNodes;
}

// 测试使用
const obj = {
  "project1.foo.a": "value",
  "project1.foo.b": "value",
  "project1.bar": "value",
  "project2.foo.a": "value",
  "project2.foo.b": "value",
  "project2.foo.c": "value",
  "project2.foo.bar": "value"
};

const treeStructure = convertToTreeselectStructure(obj);
console.log(JSON.stringify(treeStructure, null, 2));

代码说明

  1. 节点映射表:用Map存储每个节点的完整路径ID与节点对象的映射,避免重复创建节点。
  2. 路径拆分:将每个点表示法的键拆分为路径数组,逐个层级创建节点。
  3. 节点字段设置:
    • id:当前节点的完整路径,作为唯一标识
    • title:当前路径段的名称(如project1、foo)
    • has_children:判断当前节点是否为叶子节点,非路径最后一段则为true
    • level:当前节点的层级,从0开始计数
    • value:仅叶子节点赋值为原对象对应的值,非叶子节点设为undefined
    • children:存储子节点的数组
  4. 父子关联:每个非根节点创建后,会被添加到其父节点的children数组中。

输出示例(简化版)

[
  {
    "id": "project1",
    "title": "project1",
    "has_children": true,
    "level": 0,
    "value": undefined,
    "children": [
      {
        "id": "project1.foo",
        "title": "foo",
        "has_children": true,
        "level": 1,
        "value": undefined,
        "children": [
          {
            "id": "project1.foo.a",
            "title": "a",
            "has_children": false,
            "level": 2,
            "value": "value",
            "children": []
          }
        ]
      }
    ]
  }
]

内容的提问来源于stack exchange,提问作者Xyz753

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 09:20:30