我有一个平面数组,我想在node.js中构建一个树数组。 我拥有的数组就像:
var data= [
{
"id1": 1001,
"id2": 1002,
"id3": 1004,
"id4": 1007,
"id5": 1013,
"id6": 1030,
"id7": null,
"id8": null,
"id9": null,
"accountid": 1108,
"name1": "Net Income",
"name2": "Net Income Before Extraordinary Item",
"name3": "Income (Loss) from operations ",
"name4": "Net Patient Revenue",
"name5": "Gross Patient Revenue",
"name6": "Inpatient Routine Services",
"name7": null,
"name8": null,
"name9": null,
"accountname": "3000000 - INPATIENT REVENUE ",
"amt1": 6266235,
"amt2": 0,
"amt3": 7085312,
"amt4": 7010901,
"amt5": 7008743,
"amt6": 6865373,
"amt7": 7298176,
"amt8": 7481711,
"nCurMnth": 0,
"samt4": 7010901,
"id": 1030,
"parentid": 1013,
"relativelevel": 6,
"accountdetailid": null,
"variancecalc": 1,
"InfoSetID": 1108,
"InfoSetName": "3000000 - INPATIENT REVENUE ",
"DetailType": "",
"DecimalCount": 2
},
{
"id1": 1001,
"id2": 1002,
"id3": 1004,
"id4": 1007,
"id5": 1013,
"id6": 1030,
"id7": null,
"id8": null,
"id9": null,
"accountid": 2708,
"name1": "Net Income",
"name2": "Net Income Before Extraordinary Item",
"name3": "Income (Loss) from operations ",
"name4": "Net Patient Revenue",
"name5": "Gross Patient Revenue",
"name6": "Inpatient Routine Services",
"name7": null,
"name8": null,
"name9": null,
"accountname": "3000090 - INPATIENT SWING BED ",
"amt1": 190887,
"amt2": 0,
"amt3": 256581,
"amt4": 271789,
"amt5": 235998,
"amt6": 251224,
"amt7": 307154,
"amt8": 314971,
"nCurMnth": 0,
"samt4": 271789,
"id": 1030,
"parentid": 1013,
"relativelevel": 6,
"accountdetailid": null,
"variancecalc": 1,
"InfoSetID": 2708,
"InfoSetName": "3000090 - INPATIENT SWING BED ",
"DetailType": "",
"DecimalCount": 2
},
{
"id1": 1001,
"id2": 1002,
"id3": 1004,
"id4": 1007,
"id5": 1013,
"id6": 1030,
"id7": null,
"id8": null,
"id9": null,
"accountid": 1114,
"name1": "Net Income",
"name2": "Net Income Before Extraordinary Item",
"name3": "Income (Loss) from operations ",
"name4": "Net Patient Revenue",
"name5": "Gross Patient Revenue",
"name6": "Inpatient Routine Services",
"name7": null,
"name8": null,
"name9": null,
"accountname": "3999000 - SUSPENSE DAILY REV CLEAR ACCT ",
"amt1": 0,
"amt2": 0,
"amt3": 0,
"amt4": 0,
"amt5": 0,
"amt6": 0,
"amt7": 0,
"amt8": 0,
"nCurMnth": 0,
"samt4": 0,
"id": 1030,
"parentid": 1013,
"relativelevel": 6,
"accountdetailid": null,
"variancecalc": 1,
"InfoSetID": 1114,
"InfoSetName": "3999000 - SUSPENSE DAILY REV CLEAR ACCT ",
"DetailType": "",
"DecimalCount": 2
},
{
"id1": 1001,
"id2": 1002,
"id3": 1004,
"id4": 1007,
"id5": 1013,
"id6": 1031,
"id7": null,
"id8": null,
"id9": null,
"accountid": 1133,
"name1": "Net Income",
"name2": "Net Income Before Extraordinary Item",
"name3": "Income (Loss) from operations ",
"name4": "Net Patient Revenue",
"name5": "Gross Patient Revenue",
"name6": "Inpatient Ancillary Services",
"name7": null,
"name8": null,
"name9": null,
"accountname": "3070000 - INTERP - INP ",
"amt1": 36886,
"amt2": 0,
"amt3": 47968,
"amt4": 45109,
"amt5": 38047,
"amt6": 39158,
"amt7": 31290,
"amt8": 45148,
"nCurMnth": 0,
"samt4": 45109,
"id": 1031,
"parentid": 1013,
"relativelevel": 6,
"accountdetailid": null,
"variancecalc": 1,
"InfoSetID": 1133,
"InfoSetName": "3070000 - INTERP - INP ",
"DetailType": "",
"DecimalCount": 2
},
{
"id1": 1001,
"id2": 1002,
"id3": 1004,
"id4": 1007,
"id5": 1013,
"id6": 1031,
"id7": null,
"id8": null,
"id9": null,
"accountid": 1135,
"name1": "Net Income",
"name2": "Net Income Before Extraordinary Item",
"name3": "Income (Loss) from operations ",
"name4": "Net Patient Revenue",
"name5": "Gross Patient Revenue",
"name6": "Inpatient Ancillary Services",
"name7": null,
"name8": null,
"name9": null,
"accountname": "3100000 - INPATIENT ANCILLARY REV ",
"amt1": 18822593,
"amt2": 0,
"amt3": 21676463,
"amt4": 21368866,
"amt5": 20284449,
"amt6": 21344632,
"amt7": 20272660,
"amt8": 21169123,
"nCurMnth": 0,
"samt4": 21368866,
"id": 1031,
"parentid": 1013,
"relativelevel": 6,
"accountdetailid": null,
"variancecalc": 1,
"InfoSetID": 1135,
"InfoSetName": "3100000 - INPATIENT ANCILLARY REV ",
"DetailType": "",
"DecimalCount": 2
},
{
"id1": 1001,
"id2": 1002,
"id3": 1004,
"id4": 1007,
"id5": 1013,
"id6": 1031,
"id7": null,
"id8": null,
"id9": null,
"accountid": 1273,
"name1": "Net Income",
"name2": "Net Income Before Extraordinary Item",
"name3": "Income (Loss) from operations ",
"name4": "Net Patient Revenue",
"name5": "Gross Patient Revenue",
"name6": "Inpatient Ancillary Services",
"name7": null,
"name8": null,
"name9": null,
"accountname": "3100090 - SWING BED INPATIENT REV ",
"amt1": 166993,
"amt2": 0,
"amt3": 225651,
"amt4": 228349,
"amt5": 143726,
"amt6": 227736,
"amt7": 235705,
"amt8": 206381,
"nCurMnth": 0,
"samt4": 228349,
"id": 1031,
"parentid": 1013,
"relativelevel": 6,
"accountdetailid": null,
"variancecalc": 1,
"InfoSetID": 1273,
"InfoSetName": "3100090 - SWING BED INPATIENT REV ",
"DetailType": "",
"DecimalCount": 2
}
]
注意: - id1是根,其名称由name1表示,id2是id1的直接子节点,其名称是name2,类似地,id3是id2的直接子节点,其名称是name3,依此类推。
现在我想要一个由node.js中的名称表示的分层(树状)结构。
我还想知道是否有任何包可以做到这一点。
提前致谢。
树形式的预期输出如下:
Net Income
|
---------Net Income Before Extraordinary Item
|
------Income (Loss) from operations
| |
| ------Net Patient Revenue
| |
| ---------
------XYZ
答案 0 :(得分:0)
我不知道是否有这方面的包装,另一方面,它似乎可以通过旅行名称(直接与id匹配)轻松解决。这将缩进条目与relativelevel
所说的一样多,将它们放在每个对象的属性entry
中。
// Configuration
var max_attrs = 9; // Max attrs (ex: name1 .. name9).
var ename = 'entry'; // Name of the entry.
var output = {};
function process_item(item) {
// Dig into output
var dig_n = item.relativelevel;
var dig = output;
while (--dig_n) {
if (!(ename in dig))
dig[ename] = {};
dig = dig[ename];
}
// Generate entry
var i = max_attrs;
var entry;
while (--i) {
var name = item["name" + i];
if (name) {
if (!entry)
entry = name;
else {
var entry_add = {};
entry_add[name] = entry;
entry = entry_add;
}
}
};
dig[ename] = entry
}
data.forEach(function(item) {
process_item(item);
})
// tree will be in variable output
console.log(JSON.stringify(output))
答案 1 :(得分:0)
好的,我对这个好问题有一个可靠的答案。但在我进入解决方案之前,这里的细节是故事部分。
实际上这个问题解决了现代JS编程中一个非常普遍的问题,即动态获取和设置嵌套值。我开发了两种Object方法来以功能的方式满足这种需求。它们被称为Object.prototype.getNestedValue()
和Object.prototype.setNestedValue()
,它们都可以动态地获取和设置对象以及数组属性和值。
getNestedValue([prop1 [,prop2 [,prop3 ...]]])将返回嵌套属性的值。您可以像
一样调用它`myObj.getNestedValue(a,"prop2",1);`
其中myObj
是它所调用的对象,a
是动态变量(如果字符串类型表示对象属性,但如果它是数字类型则是数组索引值),“ prop2“是一个静态属性参数,最后一个是数组的索引。所有提供的参数当然都是动态的。如果您在数组中有自己的参数,则可以像getNestedValue(...[a,b,c,d]);
setNestedValue([prop1 [,prop2 [,prop3 ...]]],value)的工作原理与双胞胎完全相同,但最后一个参数是要设置的值。如果该属性不存在,它将创建一个对象或数组,取决于所提供参数的类型。同样,字符串类型参数将生成对象,而数字类型参数将生成该大小的数组。
因此,一旦我们掌握了这些工具,您就会看到受此问题影响的问题不再是问题。让我们看看代码。
Object.prototype.getNestedValue = function(...a) {
return a.length > 1 ? (this[a[0]] !== void 0 && this[a[0]].getNestedValue(...a.slice(1))) : this[a[0]];
};
Object.prototype.setNestedValue = function(...a) {
a.length > 2 ? typeof this[a[0]] === "object" && this[a[0]] !== null ? this[a[0]].setNestedValue(...a.slice(1))
: (this[a[0]] = typeof a[1] === "string" ? {} : new Array(a[1]),
this[a[0]].setNestedValue(...a.slice(1)))
: this[a[0]] = a[1];
return this;
};
var dataStr = '[{"id1":1001,"id2":1002,"id3":1004,"id4":1007,"id5":1013,"id6":1030,"id7":null,"id8":null,"id9":null,"accountid":1108,"name1":"Net Income","name2":"Net Income Before Extraordinary Item","name3":"Income (Loss) from operations ","name4":"Net Patient Revenue","name5":"Gross Patient Revenue","name6":"Inpatient Routine Services","name7":null,"name8":null,"name9":null,"accountname":"3000000 - INPATIENT REVENUE ","amt1":6266235,"amt2":0,"amt3":7085312,"amt4":7010901,"amt5":7008743,"amt6":6865373,"amt7":7298176,"amt8":7481711,"nCurMnth":0,"samt4":7010901,"id":1030,"parentid":1013,"relativelevel":6,"accountdetailid":null,"variancecalc":1,"InfoSetID":1108,"InfoSetName":"3000000 - INPATIENT REVENUE ","DetailType":"","DecimalCount":2},{"id1":1001,"id2":1002,"id3":1004,"id4":1007,"id5":1013,"id6":1030,"id7":null,"id8":null,"id9":null,"accountid":2708,"name1":"Net Income","name2":"Net Income Before Extraordinary Item","name3":"Income (Loss) from operations ","name4":"Net Patient Revenue","name5":"Gross Patient Revenue","name6":"Inpatient Routine Services","name7":null,"name8":null,"name9":null,"accountname":"3000090 - INPATIENT SWING BED ","amt1":190887,"amt2":0,"amt3":256581,"amt4":271789,"amt5":235998,"amt6":251224,"amt7":307154,"amt8":314971,"nCurMnth":0,"samt4":271789,"id":1030,"parentid":1013,"relativelevel":6,"accountdetailid":null,"variancecalc":1,"InfoSetID":2708,"InfoSetName":"3000090 - INPATIENT SWING BED ","DetailType":"","DecimalCount":2},{"id1":1001,"id2":1002,"id3":1004,"id4":1007,"id5":1013,"id6":1030,"id7":null,"id8":null,"id9":null,"accountid":1114,"name1":"Net Income","name2":"Net Income Before Extraordinary Item","name3":"Income (Loss) from operations ","name4":"Net Patient Revenue","name5":"Gross Patient Revenue","name6":"Inpatient Routine Services","name7":null,"name8":null,"name9":null,"accountname":"3999000 - SUSPENSE DAILY REV CLEAR ACCT ","amt1":0,"amt2":0,"amt3":0,"amt4":0,"amt5":0,"amt6":0,"amt7":0,"amt8":0,"nCurMnth":0,"samt4":0,"id":1030,"parentid":1013,"relativelevel":6,"accountdetailid":null,"variancecalc":1,"InfoSetID":1114,"InfoSetName":"3999000 - SUSPENSE DAILY REV CLEAR ACCT ","DetailType":"","DecimalCount":2},{"id1":1001,"id2":1002,"id3":1004,"id4":1007,"id5":1013,"id6":1031,"id7":null,"id8":null,"id9":null,"accountid":1133,"name1":"Net Income","name2":"Net Income Before Extraordinary Item","name3":"Income (Loss) from operations ","name4":"Net Patient Revenue","name5":"Gross Patient Revenue","name6":"Inpatient Ancillary Services","name7":null,"name8":null,"name9":null,"accountname":"3070000 - INTERP - INP ","amt1":36886,"amt2":0,"amt3":47968,"amt4":45109,"amt5":38047,"amt6":39158,"amt7":31290,"amt8":45148,"nCurMnth":0,"samt4":45109,"id":1031,"parentid":1013,"relativelevel":6,"accountdetailid":null,"variancecalc":1,"InfoSetID":1133,"InfoSetName":"3070000 - INTERP - INP ","DetailType":"","DecimalCount":2},{"id1":1001,"id2":1002,"id3":1004,"id4":1007,"id5":1013,"id6":1031,"id7":null,"id8":null,"id9":null,"accountid":1135,"name1":"Net Income","name2":"Net Income Before Extraordinary Item","name3":"Income (Loss) from operations ","name4":"Net Patient Revenue","name5":"Gross Patient Revenue","name6":"Inpatient Ancillary Services","name7":null,"name8":null,"name9":null,"accountname":"3100000 - INPATIENT ANCILLARY REV ","amt1":18822593,"amt2":0,"amt3":21676463,"amt4":21368866,"amt5":20284449,"amt6":21344632,"amt7":20272660,"amt8":21169123,"nCurMnth":0,"samt4":21368866,"id":1031,"parentid":1013,"relativelevel":6,"accountdetailid":null,"variancecalc":1,"InfoSetID":1135,"InfoSetName":"3100000 - INPATIENT ANCILLARY REV ","DetailType":"","DecimalCount":2},{"id1":1001,"id2":1002,"id3":1004,"id4":1007,"id5":1013,"id6":1031,"id7":null,"id8":null,"id9":null,"accountid":1273,"name1":"Net Income","name2":"Net Income Before Extraordinary Item","name3":"Income (Loss) from operations ","name4":"Net Patient Revenue","name5":"Gross Patient Revenue","name6":"Inpatient Ancillary Services","name7":null,"name8":null,"name9":null,"accountname":"3100090 - SWING BED INPATIENT REV ","amt1":166993,"amt2":0,"amt3":225651,"amt4":228349,"amt5":143726,"amt6":227736,"amt7":235705,"amt8":206381,"nCurMnth":0,"samt4":228349,"id":1031,"parentid":1013,"relativelevel":6,"accountdetailid":null,"variancecalc":1,"InfoSetID":1273,"InfoSetName":"3100090 - SWING BED INPATIENT REV ","DetailType":"","DecimalCount":2}]',
data = JSON.parse(dataStr);
getKeysToNest = (o,...k) => Object.keys(o).reduce((p,c) => {var i = k.indexOf(c.slice(0, -1));
!!~i && (p[i] = !!p[i] ? p[i].concat(c) : [c]);
return p},[]),
props = getKeysToNest(data[0],"id","name","amt"), // now we have the props to nest
nested = data.map(d => props
.reduce((n,p) => p
.reduce((o,k,i) => o.setNestedValue(...(new Array(i)).fill("child"),k,d[k]),n) ,{}));
console.log(JSON.stringify(nested,null,2));
我们实际上在这里使用getKeysToNest()
函数来收集对我们很重要的键,并将它们存储在一个数组中。然后我们将使用这个props数组来动态设置setNestedValue()方法的参数。这是一个非常简单的工作流程;
data.map(d => props
行。.reduce((n,p) => p
行中逐一采用它们。我无法弄清楚将剩下的属性放在哪里。只需再次利用setNestedValue()
将其过滤掉并在适当的级别进行处理。
如果有任何问题,我很乐意回答。