从数组动态生成的嵌套树对象
Dynamically generated nested tree object from array
给定这两个字符串,
'1|100376|100377|100378'
和
'1|100376|100377|100379|100380'
我想创建一个如下所示的对象:
{
id:"1",
children: {
id:"100376",
children: {
id:"100377",
children: {
id:"100378",
children: {},
id: "100379",
children: {
id:"100380",
children: {}
}
}
}
}
}
这是我的代码,
var tree = {};
var addTree = function(aggregateId){
if(aggregateId){
var arr = aggregateId.split('|'),
remainder = aggregateId.split('|').slice(1).join('|');
arr.reduce(function(node,id){
return node[id] || (node[id] = {});
}, tree);
}
};
addTree('1|100376|100377|100378');
addTree('1|100376|100377|100379|100380');
这会产生正确的嵌套,但不在键 id
和 children
下。我该怎么做?
{
"1": {
"100376": {
"100377": {
"100378": {},
"100379": {
"100380": {}
}
}
}
}
}
var tree = {};
var addTree = function(aggregateId) {
if (aggregateId) {
var arr = aggregateId.split('|'),
arr.reduce(function(node, id) {
if (!node.id) {
node.id = id;
node.children = {};
}
return node.children;
}, tree);
}
};
addTree('1|100376|100377|100378');
addTree('1|100376|100377|100379|100380');
console.log(JSON.stringify(tree));
// {"id":"1","children":
// {"id":"100376","children":
// {"id":"100377","children":
// {"id":"100379","children":
// {"id":"100380","children":{}}}}}}
但是,我认为您可能存在设计缺陷 - children
只能托管一个 child。您确定不希望它是一个包含节点的数组,或者更好的是 object 按键索引节点,就像您的原始情况一样?它适用于您的原始情况,因为您有从 ids 到 children 的映射;但在您提议的结构中,children
只是一个 child,总是。
EDIT 更改要求:这有点丑陋,因为 Array.prototype.find
仍然不普遍可用。可以使用 .filter()[0]
作为 hack,但效率很低。所以:
var tree = [];
var addTree = function(aggregateId) {
if (aggregateId) {
var arr = aggregateId.split('|'),
arr.reduce(function(children, id) {
var node, i;
for (i = 0; i < children.length; i++) {
if (children[i].id == id) {
node = children[i];
break;
}
}
if (!node) {
children.push(node = {
id: id,
children: []
});
}
return node.children;
}, tree);
}
};
你已经完成了一半。您需要做的就是post-处理您的输出以创建所需的表单,这就像
一样简单
function makeTree(tree) {
if (!tree) return [];
return Object.keys(tree) . map(function(key) {
return { id: key, children: makeTree(tree[key]) };
});
}
这会输出一个在数组中包含子项的结构,这是您需要的,以防有多个子项,正如另一个 poster 指出的那样。输出是:
{
id:"1",
children: [
{
id:"100376",
children: [
{
id:"100377",
children: [
{
id:"100378",
children: []
},
{
id: "100379",
children: [
{
id:"100380",
children: []
}
]
}
]
}
]
}
]
}
以下构建中间表示的代码可能比您编写的代码更简洁:
function addTree(tree, input) {
function addNodes(node, ids) {
if (!ids.length) return; // exit recursion when done
var id = ids.shift(); // pick off next id
var subnode = node[id] = node[id] || { }; // find or create node
addNodes(subnode, ids); // recursively update
}
addNodes(tree, input.split('|'));
}
其工作方式是内部函数 addNodes
使用数组 ids
中的 ID 更新 node
。它检查以确保有更多的 id 要添加,然后选择第一个,查看相应的节点是否已经存在,如果没有创建一个,然后将此 id 添加到该子节点。
对您要处理的所有字符串继续调用 addTree
。然后,post-处理tree
得到最终的输出。
使用这个:
> var input1 = '1|100376|100377|100378';
> var input2 = '1|100376|100379|100380';
> var tree = {};
> addTree(tree, input1) // add initial input
> tree
<"{
"1": {
"100376": {
"100377": {
"100378": {}
}
}
}
}"
> addTree(tree, input2) // add some more input
> tree
< "{
"1": {
"100376": {
"100377": {
"100378": {}
},
"100379": {
"100380": {}
}
}
}
}"
> makeTree(tree)
< "[
{
"id": "1",
"children": [
{
"id": "100376",
"children": [
{
"id": "100377",
"children": [
{
"id": "100378",
"children": []
}
]
},
{
"id": "100379",
"children": [
{
"id": "100380",
"children": []
}
]
}
]
}
]
}
]"
你的问题描述的不是很清楚。但是,如果您想要一种简单的方法来生成树,您所要做的就是在竖线字符 ("|"
) 处拆分字符串,然后向后读取数组。
如果你想有多个children,你可以很容易地调整下面的逻辑使.children
成为一个数组。然后,您所要做的就是 o.children.push(p)
而不是 o.children = p
.
由于无法在 JavaScript 中 right-reduce,您可以 reverse
the array first, before reduce
-ing
var aggregate = function (s) {
return s.split("|").reverse().reduce(function (p, c) {
var o = {};
o.id = c;
o.children = p;
return o;
}, {});
}
console.log(aggregate("'1|100376|100377|100378'"));
给定这两个字符串,
'1|100376|100377|100378'
和
'1|100376|100377|100379|100380'
我想创建一个如下所示的对象:
{
id:"1",
children: {
id:"100376",
children: {
id:"100377",
children: {
id:"100378",
children: {},
id: "100379",
children: {
id:"100380",
children: {}
}
}
}
}
}
这是我的代码,
var tree = {};
var addTree = function(aggregateId){
if(aggregateId){
var arr = aggregateId.split('|'),
remainder = aggregateId.split('|').slice(1).join('|');
arr.reduce(function(node,id){
return node[id] || (node[id] = {});
}, tree);
}
};
addTree('1|100376|100377|100378');
addTree('1|100376|100377|100379|100380');
这会产生正确的嵌套,但不在键 id
和 children
下。我该怎么做?
{
"1": {
"100376": {
"100377": {
"100378": {},
"100379": {
"100380": {}
}
}
}
}
}
var tree = {};
var addTree = function(aggregateId) {
if (aggregateId) {
var arr = aggregateId.split('|'),
arr.reduce(function(node, id) {
if (!node.id) {
node.id = id;
node.children = {};
}
return node.children;
}, tree);
}
};
addTree('1|100376|100377|100378');
addTree('1|100376|100377|100379|100380');
console.log(JSON.stringify(tree));
// {"id":"1","children":
// {"id":"100376","children":
// {"id":"100377","children":
// {"id":"100379","children":
// {"id":"100380","children":{}}}}}}
但是,我认为您可能存在设计缺陷 - children
只能托管一个 child。您确定不希望它是一个包含节点的数组,或者更好的是 object 按键索引节点,就像您的原始情况一样?它适用于您的原始情况,因为您有从 ids 到 children 的映射;但在您提议的结构中,children
只是一个 child,总是。
EDIT 更改要求:这有点丑陋,因为 Array.prototype.find
仍然不普遍可用。可以使用 .filter()[0]
作为 hack,但效率很低。所以:
var tree = [];
var addTree = function(aggregateId) {
if (aggregateId) {
var arr = aggregateId.split('|'),
arr.reduce(function(children, id) {
var node, i;
for (i = 0; i < children.length; i++) {
if (children[i].id == id) {
node = children[i];
break;
}
}
if (!node) {
children.push(node = {
id: id,
children: []
});
}
return node.children;
}, tree);
}
};
你已经完成了一半。您需要做的就是post-处理您的输出以创建所需的表单,这就像
一样简单function makeTree(tree) {
if (!tree) return [];
return Object.keys(tree) . map(function(key) {
return { id: key, children: makeTree(tree[key]) };
});
}
这会输出一个在数组中包含子项的结构,这是您需要的,以防有多个子项,正如另一个 poster 指出的那样。输出是:
{
id:"1",
children: [
{
id:"100376",
children: [
{
id:"100377",
children: [
{
id:"100378",
children: []
},
{
id: "100379",
children: [
{
id:"100380",
children: []
}
]
}
]
}
]
}
]
}
以下构建中间表示的代码可能比您编写的代码更简洁:
function addTree(tree, input) {
function addNodes(node, ids) {
if (!ids.length) return; // exit recursion when done
var id = ids.shift(); // pick off next id
var subnode = node[id] = node[id] || { }; // find or create node
addNodes(subnode, ids); // recursively update
}
addNodes(tree, input.split('|'));
}
其工作方式是内部函数 addNodes
使用数组 ids
中的 ID 更新 node
。它检查以确保有更多的 id 要添加,然后选择第一个,查看相应的节点是否已经存在,如果没有创建一个,然后将此 id 添加到该子节点。
对您要处理的所有字符串继续调用 addTree
。然后,post-处理tree
得到最终的输出。
使用这个:
> var input1 = '1|100376|100377|100378';
> var input2 = '1|100376|100379|100380';
> var tree = {};
> addTree(tree, input1) // add initial input
> tree
<"{
"1": {
"100376": {
"100377": {
"100378": {}
}
}
}
}"
> addTree(tree, input2) // add some more input
> tree
< "{
"1": {
"100376": {
"100377": {
"100378": {}
},
"100379": {
"100380": {}
}
}
}
}"
> makeTree(tree)
< "[
{
"id": "1",
"children": [
{
"id": "100376",
"children": [
{
"id": "100377",
"children": [
{
"id": "100378",
"children": []
}
]
},
{
"id": "100379",
"children": [
{
"id": "100380",
"children": []
}
]
}
]
}
]
}
]"
你的问题描述的不是很清楚。但是,如果您想要一种简单的方法来生成树,您所要做的就是在竖线字符 ("|"
) 处拆分字符串,然后向后读取数组。
如果你想有多个children,你可以很容易地调整下面的逻辑使.children
成为一个数组。然后,您所要做的就是 o.children.push(p)
而不是 o.children = p
.
由于无法在 JavaScript 中 right-reduce,您可以 reverse
the array first, before reduce
-ing
var aggregate = function (s) {
return s.split("|").reverse().reduce(function (p, c) {
var o = {};
o.id = c;
o.children = p;
return o;
}, {});
}
console.log(aggregate("'1|100376|100377|100378'"));