简体   繁体   English

使用 JavaScript 将嵌套的 Json 树转换为对象的 JSON 数组

[英]Convert nested Json tree into JSON array of objects using JavaScript

I have a API which return JSON tree format in parent/child relation based on "ParentId" in each object.我有一个 API,它根据每个对象中的“ParentId”以父/子关系返回 JSON 树格式。 Below is the example of JSON下面是 JSON 的例子

[
{
  "label": "search me",
  "value": "searchme",
  "children": [
    {
      "label": "search me too",
      "value": "searchmetoo",
      "children": [
        {
          "label": "No one can get me",
          "value": "anonymous"
        }
      ]
    }
  ]
},
{
  "label": "search me2",
  "value": "searchme2",
  "children": [
    {
      "label": "search me too2",
      "value": "searchmetoo2",
      "children": [
        {
          "label": "No one can get me2",
          "value": "anonymous2"
        }
      ]
    }
  ]
}
]

Which need to be converted into array of object where each object will represent the node element, with a unique primary key,Where "parentid" is null it will be root nodes and other will be child node of their parent node.其中需要转换为对象数组,其中每个对象将代表节点元素,具有唯一的主键,其中“parentid”为空将是根节点,其他将是其父节点的子节点。

the final array of objects as bellow最终的对象数组如下

[
  {
    DIAGID: 1,
    DIAGNOSIS: "Certain infectious or parasitic diseases ",
    DIAGTYPE: "Chapter",
    PARENTID: null,
  },
  {
    DIAGID: 2,
    DIAGNOSIS: "Gastroenteritis or colitis of infectious origin  ",
    DIAGTYPE: "Section",
    PARENTID: 1,
  },
  {
    DIAGID: 3,
    DIAGNOSIS: "Bacterial intestinal infections",
    DIAGTYPE: "Category",
    PARENTID: 2,
  },
]

You could take a recursive method for Array#flatMap and store parent for the next call.您可以对Array#flatMap使用递归方法并为下一次调用存储parent

 const flatTree = (parent = null) => ({ children = [], ...object }) => [ { ...object, parent }, ...children.flatMap(flatTree(object.id)) ], tree = [{ id: 0, label: 'search me', value: 'searchme', children: [{ id: 1, label: 'search me too', value: 'searchmetoo', children: [{ id: 2, label: 'No one can get me', value: 'anonymous' }] }] }], flat = tree.flatMap(flatTree()); console.log(flat);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

Assuming you will be getting data as array of objects.假设您将以对象数组的形式获取数据。 A simpler and understandable recursive function一个更简单易懂的递归函数

 const data = [{ label: 'search me', value: 'searchme', children: [{ label: 'No one can get me1', value: 'anonymous', }, { label: 'search me too', value: 'searchmetoo', children: [{ label: 'No one can get me', value: 'anonymous', }, ], }, ], }] let final_data = []; let index = 1; let parentID = 1; let pushInFinal = (root, parent) => { root.forEach((item) => { final_data.push({ "DIAGID": index, "DIAGNOSIS": item.label, "DIAGTYPE": item.value, "PARENTID": parent, }, ) if (item.hasOwnProperty('children')) { parentID = index++; pushInFinal(item.children, parentID) } }) } pushInFinal(data, null) console.log(final_data)

Here is a recursive function dfs that performs a pre-order traversal through the input tree, and passes along a counter that feeds the id property that will be used in the output.这是一个递归函数dfs ,它通过输入树执行预序遍历,并传递一个计数器,该计数器提供将在输出中使用的id属性。 Also the current node's id is passed as parentId to the recursive call:此外,当前节点的id作为parentId传递给递归调用:

 const dfs = ({children=[], ...node}, counter={id: 1}, parentId=null) => [{ ...node, id: counter.id++, parentId}].concat( children.flatMap(child => dfs(child, counter, node.id)) ); const response = {"label":"search me","value":"searchme","children":[{"label":"search me too","value":"searchmetoo","children":[{"label":"No one can get me","value":"anonymous"}]}]}; const result = dfs(response); console.log(result);

I was going to say a recursive tree walk is all you need, but you do do the same thing easily with a generator:我想说递归树遍历就是你所需要的,但是你可以用生成器轻松地做同样的事情:

function *visitNodes( root, parent = null, id = 0 ) {
  
  const node = {
    ...root,
    id : ++id,
    parentId = parent ? parent.id : null
  };
  delete node.children;
  
  yield node;
  
  for (const child of root.children) {
    yield *visitNodes(child, node, id);
  }
  
}

Having defined the generator, you can either iterate over the nodes:定义生成器后,您可以遍历节点:

for (const node of visitNodes( tree ) ) {
  // do something useful with node here
}

You can convert it into a list easily, either with the spread operator:您可以使用扩展运算符轻松将其转换为列表:

const nodes  = [...visitNodes(tree)];

or by using Array.from() :或使用Array.from()

const nodes = Array.from( visitNodes(tree) );

A single recursively implemented collecting reduce er functionality does the job.一个递归实现的收集reduce er 功能可以完成这项工作。

It utilizes a collector object as the reduce method's 2nd argument (and the reducer's initial value).它使用一个collector对象作为reduce方法的第二个参数(以及reducer 的初始值)。 The collector 's result array collects any item. collectorresult数组收集任何项目。 And count gets incremented constantly and assigned as a collected item's DIAGID whereas parentId gets updated as needed in order to always reflect the current recursive call stack thus an item's corresponding (and correct) PARENTID ...并且count不断增加并分配为收集项目的DIAGIDparentId根据需要更新以始终反映当前的递归调用堆栈,因此项目对应的(和正确的) PARENTID ...

 function collectAndMapNestedItemRecursively(collector, item) { let { count = 0, parentId = null, result } = collector; const { label, value, children } = item; result.push({ "DIAGID": ++count, "DIAGNOSIS": label, "DIAGTYPE": value, "PARENTID": parentId, }); if (Array.isArray(children)) { count = children.reduce( collectAndMapNestedItemRecursively, { count, parentId: count, result } ).count; } return { count, parentId, result }; } const sampleData = [{ "label": "FOO", "value": "foo", "children": [{ "label": "FOO BAR", "value": "fooBar", "children": [{ "label": "FOO BAR BAZ", "value": "fooBarBaz", }], }, { "label": "FOO BIZ", "value": "fooBiz", "children": [{ "label": "FOO BIZ BUZ", "value": "fooBizBuz", }], }], }, { "label": "BAR", "value": "bar", "children": [{ "label": "BAR BAZ", "value": "barBaz", "children": [{ "label": "BAR BAZ BIZ", "value": "barBazBiz", }], }, { "label": "BAR BUZ", "value": "barBuz", "children": [{ "label": "BAR BUZ BOZ", "value": "barBuzBoz", }], }], }]; console.log( sampleData.reduce( collectAndMapNestedItemRecursively, { result: [] }, ).result );
 .as-console-wrapper { min-height: 100%!important; top: 0; }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM