下面是我的输入内容:
input1 =
[{
"201609": 5,
"201610": 7,
"201611": 9,
"201612": 10,
"FY17": 24,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 3,
"201610": 6,
"201611": 9,
"201612": 8
"FY17": 18,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 1,
"201610": 2,
"201611": 3,
"201612": 5
"FY17": 6,
"careerLevel": "CL1"
},
{
"201609": 2,
"201610": 4,
"201611": 6,
"201612": 9
"FY17": 12,
"careerLevel": "CL2"
}
]
}]
}]
input2 =
[{
"201609": 4,
"201610": 8,
"201611": 12,
"FY17": 24,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 9,
"201610": 2,
"201611": 7,
"FY17": 18,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 3,
"201610": 6,
"201611": 9,
"FY17": 18,
"careerLevel": "CL1"
},
{
"201609": 7,
"201610": 8,
"201611": 9,
"FY17": 24,
"careerLevel": "CL2"
}
]
}]
}]
输出=输入1 +输入2。
我的输出应具有所有数值的总和。如果没有 找到匹配的键如“ 201612” ,它仍应保留在 输出。
[{
"201609": 9,
"201610": 15,
"201611": 21,
"201612": 10,
"FY17": 48,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 12,
"201610": 8,
"201611": 16,
"201612": 8,
"FY17": 24,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 4,
"201610": 8,
"201611": 12,
"201612": 5,
"FY17": 24,
"careerLevel": "CL1"
},
{
"201609": 9,
"201610": 12,
"201611": 15,
"201612": 9,
"FY17": 36,
"careerLevel": "CL2"
}
]
}]
}]
以下是我要尝试做的事情:
var output = [{}];
for(let i in input){
for (let key in input[i]){
if (output[0].hasOwnProperty(key)) {
output[0][key]+=input[i][key];
}else{
output[0][key]=input[i][key];
}
}
}
console.log(JSON.stringify(output)); // errors out
但是这不能给我想要的结果,因为它不能像上面那样对分层的json结构求和。
答案 0 :(得分:1)
让我们首先编写主要的merge
函数:
function merge(x, y, fn) {
if (isNotCompound(x) && isNotCompound(y)) {
return fn(x, y);
}
if (isArray(x) && isArray(y)) {
return mergeArray(x, y, fn);
}
if (isObject(x) && isObject(y)) {
return mergeObject(x, y, fn);
}
throw new Error('the two input values are not of the same compound type');
}
merge
函数相当于根据其输入值x
和y
的类型进行分派。如果发现它们都是原始类型(即它们既不是数组也不是对象),则根据fn
函数将它们合并。否则,将选择适当的帮助程序功能来进行遍历。
因此让我们实现调度所必需的 type谓词:
const isArray = x => Array.isArray(x);
const isObject = x => Object.prototype.toString.call(x) === '[object Object]';
const isNotCompound = x => !isArray(x) && !isObject(x);
现在只需编写mergeArray
和mergeObject
。 mergeArray
的一种可能的实现如下:
function mergeArray(xs, ys, fn) {
if (xs.length !== ys.length) throw new Error('the two arrays must be of the same size');
let r = [];
for (let i = 0; i < xs.length; i++) {
r.push(merge(xs[i], ys[i], fn));
}
return r;
}
如图所示,mergeArray
要求两个数组的大小相同。对于mergeObject
,一种实现方式如下:
function mergeObject(obj1, obj2, fn) {
let r = {};
for (let key of Object.keys(obj1)) {
r[key] = obj2[key] ? merge(obj1[key], obj2[key], fn) : obj1[key];
}
for (let key of Object.keys(obj2)) {
if (r[key]) continue;
r[key] = obj2[key];
}
return r;
}
值得注意的是,值组合了通用键,而未共享的属性则直接传播到结果对象。
最后,可以通过传递以下输入函数来获得所需的合并策略:
const isNumber = x => typeof x === 'number';
const add = (x, y) => isNumber(x) && isNumber(y) ? x + y : (x || y);
如果两个输入的原始值都是数字,则返回它们的和,否则返回两个碰巧定义的值。
我们终于可以执行:
console.log(JSON.stringify(merge(input1, input2, add)));
完整的源代码如下。
const isArray = x => Array.isArray(x);
const isObject = x => Object.prototype.toString.call(x) === '[object Object]';
const isNotCompound = x => !isArray(x) && !isObject(x);
function merge(x, y, fn) {
if (isNotCompound(x) && isNotCompound(y)) {
return fn(x, y);
}
if (isArray(x) && isArray(y)) {
return mergeArray(x, y, fn);
}
if (isObject(x) && isObject(y)) {
return mergeObject(x, y, fn);
}
throw new Error('the two input values are not of the same compound type');
};
function mergeArray(xs, ys, fn) {
if (xs.length !== ys.length) throw new Error('the two arrays must be of the same size');
let r = [];
for (let i = 0; i < xs.length; i++) {
r.push(merge(xs[i], ys[i], fn));
}
return r;
}
function mergeObject(obj1, obj2, fn) {
let r = {};
for (let key of Object.keys(obj1)) {
r[key] = obj2[key] ? merge(obj1[key], obj2[key], fn) : obj1[key];
}
for (let key of Object.keys(obj2)) {
if (r[key]) continue;
r[key] = obj2[key];
}
return r;
}
let input1 = [{
"201609": 5,
"201610": 7,
"201611": 9,
"201612": 10,
"FY17": 24,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 3,
"201610": 6,
"201611": 9,
"201612": 8,
"FY17": 18,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 1,
"201610": 2,
"201611": 3,
"201612": 5,
"FY17": 6,
"careerLevel": "CL1"
},
{
"201609": 2,
"201610": 4,
"201611": 6,
"201612": 9,
"FY17": 12,
"careerLevel": "CL2"
}
]
}]
}];
let input2 = [{
"201609": 4,
"201610": 8,
"201611": 12,
"FY17": 24,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 9,
"201610": 2,
"201611": 7,
"FY17": 18,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 3,
"201610": 6,
"201611": 9,
"FY17": 18,
"careerLevel": "CL1"
}, {
"201609": 7,
"201610": 8,
"201611": 9,
"FY17": 24,
"careerLevel": "CL2"
}]
}]
}];
const isNumber = x => typeof x === 'number';
const add = (x, y) => isNumber(x) && isNumber(y) ? x + y : (x || y);
console.log(JSON.stringify(merge(input1, input2, add)));
答案 1 :(得分:0)
创建一个递归函数,并在内部使用forEach
迭代数组
流程是这样的,而不是同时循环input1
和input2
数组,循环其中的一个,如果键的值是一个数字,则将其添加到另一个数组中相同键的值。如果键的值是一个数组,则使用新的参数
var input1 = [{
"201609": 5,
"201610": 7,
"201611": 9,
"201612": 10,
"FY17": 24,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 3,
"201610": 6,
"201611": 9,
"201612": 8,
"FY17": 18,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 1,
"201610": 2,
"201611": 3,
"201612": 5,
"FY17": 6,
"careerLevel": "CL1"
},
{
"201609": 2,
"201610": 4,
"201611": 6,
"201612": 9,
"FY17": 12,
"careerLevel": "CL2"
}
]
}]
}]
var input2 = [{
"201609": 4,
"201610": 8,
"201611": 12,
"FY17": 24,
"metric": "metric1",
"careerLevelGroups": [{
"201609": 9,
"201610": 2,
"201611": 7,
"FY17": 18,
"careerLevel": "Senior Managing Director",
"careerLevels": [{
"201609": 3,
"201610": 6,
"201611": 9,
"FY17": 18,
"careerLevel": "CL1"
},
{
"201609": 7,
"201610": 8,
"201611": 9,
"FY17": 24,
"careerLevel": "CL2"
}
]
}]
}]
// A function which will take input2 and input1 array
function loopArray(arrayToBeLooped, addingArray) {
// now looping over the array
arrayToBeLooped.forEach(function(item, index) {
// item is each object,here checking if the value of object key is array or number
for (let keys in item) {
// if number then find the same key from other array and add the value
if (typeof item[keys] === 'number') {
addingArray[index][keys] = addingArray[index][keys] + item[keys]
}
if (Array.isArray(item[keys])) {
// if the type of value is another array for example
// careerLevelGroups & careerLevels then it is basically same
// as looping over array input1 & input2
// so calling the same loopArray function and passing different
// parameter but the object remains same
loopArray(arrayToBeLooped[index][keys], addingArray[index][keys])
}
}
})
}
loopArray(input2, input1)
console.log(input1)