使用内部对象javascript将平面数据转换为分层数据

时间:2017-04-07 14:08:11

标签: javascript

我遇到了将简单的平面数据转换为分层的常见问题。我已经找到了关于这个的多个主题,但仍然无法获得如何将平面数据完全转换为必要的分层格式

这是我的json

    [
  {
    "id": 1,
    "name": "Sponsor",
    "description": null,
    "parentId": null
  },
  {
    "id": 2,
    "name": "Class",
    "description": null,
    "parentId": 1
  },
  {
    "id": 3,
    "name": "Study",
    "description": null,
    "parentId": 2
  },
  {
    "id": 4,
    "name": "Site",
    "description": null,
    "parentId": 3
  }
]

我需要获得这样的格式

  [
    {
      "data":{
        "id": 1,
        "name":"Sponsor",
        "description":null,
        "parentId":"null"
      },
      "children":[
        {
          "data":{
            "id": 2,
            "name":"Class",
            "description":null,
            "parentId":"1"
          },
          "children":[
            {
              "data":{
                "id": 3,
                "name":"Study",
                "description":null,
                "parentId":"2"
              },
             "children": [
                {
                   "data":{ 
                     "id": 4,
                     "name":"Site",
                     "description":null,
                     "parentId":"3"
                   }
                 }
              ]
            }
          ]
        }
      ]
    }
  ]

这是我的功能

    flatToHierarchy(flat) {

    let roots = [];
    let all = {};

    flat.forEach(function (item) {
      all[item.id] = item
    });

    Object.keys(all).forEach(function (id) {
      let item = all[id];
      if (item.parentId === null) {
        roots.push(item)
      } else if (item.parentId in all) {
        let p = all[item.parentId];
        if (!('Children' in p)) {
          p.children = []
        }
        p.children.push(item)
      }
    });

    console.log(roots);
    return roots
  }

输出

    [
  {
    "id": 1,
    "name": "Sponsor",
    "description": null,
    "parentId": null,
    "children": [
      {
        "id": 2,
        "name": "Class",
        "description": "Together",
        "parentId": 1,
        "children": [
          {
            "id": 3,
            "name": "Study",
            "description": "browsing data",
            "parentId": 2,
            "children": [
              {
                "id": 4,
                "name": "Site",
                "description": null,
                "parentId": 3,
                "children": []
              }
            ]
          }
        ]
      }
    ]
  }
  ]

我非常接近渴望的结果。有人可以帮我解决这个问题吗?

被修改

@ Someone3 提供的正确答案 这是针对我的需求略微修改的代码

    flatToHierarchy (flat) {

    let roots = [];
    let all = {};
    let ids = [];

    flat.forEach(function (item) {
      let itemId = item.id;
      let convertedItem = function (id) {
        let newItem = {};
        newItem['data'] = id;
        return newItem;
      } ;
      all[itemId] = convertedItem(item);
      ids.push(itemId);
    });

    for (let i = 0; i < ids.length; i++) {
      let id = ids[i];
      let convertedItem = all[id];
      let parentId = convertedItem.data.parentId;

      if (parentId === null) {
        roots.push(convertedItem);
      } else if (parentId in all) {
        let p = all[parentId];
        if (!('children' in p)) {
          p.children = []
        }
        p.children.push(convertedItem)
      }
    }
    return roots
  }

2 个答案:

答案 0 :(得分:1)

以下代码是您的具体情况的完整源代码。我修改并添加了源代码中的几行。 请注意,此代码假定父项在其子项之前始终插入此树。如果此假设并非总是如此,那么您的代码需要进行更改。

let flatData = [
  {
    "id": 1,
    "name": "Sponsor",
    "description": null,
    "parentId": null
  },
  {
    "id": 2,
    "name": "Class",
    "description": null,
    "parentId": 1
  },
  {
    "id": 3,
    "name": "Study",
    "description": null,
    "parentId": 2
  },
  {
    "id": 4,
    "name": "Site",
    "description": null,
    "parentId": 3
  }
];

function convertItem(item) {
  let newItem = {};
  newItem.data = item;  
  return newItem;
}

function flatToHierarchy(flat) {

    let roots = [];
    let all = {};
    let ids = [];

    flat.forEach(function (item) {
      let itemId = item.id;
      let convertedItem = convertItem(item);
      all[itemId] = convertedItem;
      ids.push(itemId);
    });

    // We use ids array instead of object to maintain its previous order.
    for (let i = 0; i < ids.length; i++) {
      let id = ids[i];
      let convertedItem = all[id];
      let parentId = convertedItem.data.parentId;

      if (parentId === null) {
        delete convertedItem.data.parentId;
        delete convertedItem.data.id;
        roots.push(convertedItem);
      } else if (parentId in all) {
        let p = all[parentId];
        if (!('Children' in p)) {
          p.children = []
        }
        delete convertedItem.data.parentId;
        delete convertedItem.data.id;
        p.children.push(convertedItem)
      }
    };

    console.log(roots);
    return roots
  }

  flatToHierarchy(flatData);

我们可以在推送之前分解两个删除。

答案 1 :(得分:0)

我的方式如何?

function flatToHierarchy (flatData) {
  const tree = JSON.parse(JSON.stringify(flatData)) // or using `cloneDeep` of lodash library to not side-effect with flatData

  tree.forEach((item) => {
      item.children = tree.filter((element) => element.parent_id === dept.id)
  });
  const roots = tree.filter((item) => item.parent_id === 0)
  return roots
}