Json:JSON数组的总和

时间:2018-06-28 16:28:07

标签: javascript arrays json typescript

下面是我的输入内容:

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结构求和。

2 个答案:

答案 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函数相当于根据其输入值xy的类型进行分派。如果发现它们都是原始类型(即它们既不是数组也不是对象),则根据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);

现在只需编写mergeArraymergeObjectmergeArray的一种可能的实现如下:

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迭代数组 流程是这样的,而不是同时循环input1input2数组,循环其中的一个,如果键的值是一个数字,则将其添加到另一个数组中相同键的值。如果键的值是一个数组,则使用新的参数

调用相同的递归函数。

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)