【问题标题】:Json: sum values of json arrayJson:json数组的总和值
【发布时间】:2018-06-28 16:28:06
【问题描述】:

以下是我的输入:

输入1 =

  [{

    "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"
            }
        ]
    }]
}]

输入2 =

   [{

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

【问题讨论】:

    标签: javascript arrays json typescript


    【解决方案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 函数进行合并。否则,将选择适当的辅助函数进行遍历。

    因此,让我们实现调度所需的类型谓词

       const isArray = x => Array.isArray(x);
       const isObject = x => Object.prototype.toString.call(x) === '[object Object]';
       const isNotCompound = x => !isArray(x) && !isObject(x);
    

    现在是写mergeArraymergeObject 的问题。 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)));

    【讨论】:

      【解决方案2】:

      创建一个递归函数,并在其中使用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)

      【讨论】:

      • 谢谢,递归在你的脑海中,但我不明白。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-08
      • 1970-01-01
      • 1970-01-01
      • 2020-06-27
      • 1970-01-01
      • 2020-04-24
      • 2023-04-03
      相关资源
      最近更新 更多