[英]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. collector
的result
数组收集任何项目。 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
不断增加并分配为收集项目的DIAGID
而parentId
根据需要更新以始终反映当前的递归调用堆栈,因此项目对应的(和正确的) 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.