我有一个称为树的函数,该函数接收对象数组(作为数据库中的数据字段)和键字符串数组。该函数遍历rowsArray,并基于keyArray递归创建具有嵌套属性的对象。
const tree = (rowsArray, keysArray) => {
return rows.reduce((acc, row) => {
const groupBy = (row, keys,) => {
const [first, ...rest] = keys;
if (!first) return [row];
return {
[row[first]]: groupBy(row, rest),
}
};
acc = {...groupBy(row, keys), ...acc};
return acc;
}, {});
}
数据如下:
const data = [{
ID: 1,
Main: "Financial",
Sub: "Forecasts",
Detail: "General"
}, {
ID: 2,
Main: "Financial",
Sub: "HR",
Detail: "Headcount"
}];
const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1);
当我记录结果时,我得到:
/*
// actual output
{
Financial: {
Forecasts: {
General: [Array]
}
}
}
我想得到以下信息:
// expected
{
Financial: {
Forecasts: {
General: [Array]
},
HR: {
Headcount: [Array]
}
}
}
*/
问题是,主函数中的acc变量被覆盖,并且我得到了新的对象,而不是累积的,而且我不太确定如何递归地构建该对象。我试图将acc实例传递给groupBy函数(以记住以前的结果),但是没有运气。
您是否知道如何重写树函数或groupBy函数以实现我的目标?谢谢!
答案 0 :(得分:1)
问题在于您的合并功能不是 deep 。当您将值分配给累加器时,您将覆盖现有属性-在这种情况下为Financial
。
我包含了一个深层合并功能from here,现在它可以工作了。
我还修复了您遇到的一些参考错误:
rows
=> rowsArray
keys
= keysArray
// deep merge function
function merge(current, update) {
Object.keys(update).forEach(function(key) {
// if update[key] exist, and it's not a string or array,
// we go in one level deeper
if (current.hasOwnProperty(key) &&
typeof current[key] === 'object' &&
!(current[key] instanceof Array)) {
merge(current[key], update[key]);
// if update[key] doesn't exist in current, or it's a string
// or array, then assign/overwrite current[key] to update[key]
} else {
current[key] = update[key];
}
});
return current;
}
const tree = (rowsArray, keysArray) => {
return rowsArray.reduce((acc, row) => {
const groupBy = (row, keys, ) => {
const [first, ...rest] = keys;
if (!first) return [row];
return {
[row[first]]: groupBy(row, rest),
}
};
acc = merge(groupBy(row, keysArray), acc);
return acc;
}, {});
}
const data = [{
ID: 1,
Main: "Financial",
Sub: "Forecasts",
Detail: "General"
}, {
ID: 2,
Main: "Financial",
Sub: "HR",
Detail: "Headcount"
}];
const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1);
答案 1 :(得分:1)
您可以这样做:
function tree(rows, keys) {
return rows.reduce( (acc, row) => {
keys.reduce( (parent, key, i) =>
parent[row[key]] = parent[row[key]] || (i === keys.length - 1 ? [row] : {})
, acc);
return acc;
}, {});
}
const data = [{ID: 1,Main: "Financial",Sub: "Forecasts",Detail: "General"}, {ID: 2,Main: "Financial",Sub: "HR", Detail: "Headcount" }];
const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1);
请注意,传播语法会产生浅表副本。相反,在此解决方案中,累加器被传递到内部reduce
。因此,我们实际上将新行的分层数据合并到了现场的累加器中。
答案 2 :(得分:1)
您可以迭代键并为最后一个键获取一个对象(而不是最后一个键)或将数组作为最后一个键,然后将数据推入数组。
const tree = (rowsArray, keysArray) => {
return rowsArray.reduce((acc, row) => {
keysArray
.map(k => row[k])
.reduce((o, k, i, { length }) => o[k] = o[k] || (i + 1 === length ? []: {}), acc)
.push(row);
return acc;
}, {});
}
const data = [{ ID: 1, Main: "Financial", Sub: "Forecasts", Detail: "General" }, { ID: 2, Main: "Financial", Sub: "HR", Detail: "Headcount" }];
const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1);
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 3 :(得分:1)
您可以遍历data
并根据提供的keys
创建一个唯一密钥,然后通过深度克隆递归地生成输出结构。
const data = [{
ID: 1,
Main: "Financial",
Sub: "Forecasts",
Detail: "General"
}, {
ID: 2,
Main: "Financial",
Sub: "HR",
Detail: "Headcount"
}];
function generateKey(keys,json){
return keys.reduce(function(o,i){
o += json[i] + "_";
return o;
},'');
}
function merge(first,second){
for(var i in second){
if(!first.hasOwnProperty(i)){
first[i] = second[i];
}else{
first[i] = merge(first[i],second[i]);
}
}
return first;
}
function generateTree(input,keys){
let values = input.reduce(function(o,i){
var key = generateKey(keys,i);
if(!o.hasOwnProperty(key)){
o[key] = [];
}
o[key].push(i);
return o;
},{});
return Object.keys(values).reduce(function(o,i){
var valueKeys = i.split('_');
var oo = {};
for(var index = valueKeys.length -2; index >=0 ;index--){
var out = {};
if(index === valueKeys.length -2){
out[valueKeys[index]] = values[i];
}else{
out[valueKeys[index]] = oo;
}
oo = out;
}
o = merge(o,oo);
return o;
},{});
}
console.log(generateTree(data,["Main", "Sub", "Detail"]));
jsFiddle演示-https://jsfiddle.net/6jots8Lc/