【问题标题】:How to sum the values of a JavaScript object?如何对 JavaScript 对象的值求和?
【发布时间】:2013-05-03 04:36:52
【问题描述】:

我想对一个对象的值求和。

我已经习惯了 Python:

sample = { 'a': 1 , 'b': 2 , 'c':3 };
summed =  sum(sample.itervalues())     

以下代码有效,但代码量很大:

function obj_values(object) {
  var results = [];
  for (var property in object)
    results.push(object[property]);
  return results;
}

function list_sum( list ){
  return list.reduce(function(previousValue, currentValue, index, array){
      return previousValue + currentValue;
  });
}

function object_values_sum( obj ){
  return list_sum(obj_values(obj));
}

var sample = { a: 1 , b: 2 , c:3 };
var summed =  list_sum(obj_values(a));
var summed =  object_values_sum(a)

我是否遗漏了任何明显的东西,还是就是这样?

【问题讨论】:

    标签: javascript object javascript-objects


    【解决方案1】:

    可以这么简单:

    const sumValues = obj => Object.values(obj).reduce((a, b) => a + b);
    

    引用 MDN:

    Object.values() 方法返回给定对象自己的可枚举属性值的数组,其顺序与for...in 循环提供的顺序相同(区别在于 for-in 循环也枚举原型链中的属性)。

    来自Object.values() on MDN

    reduce() 方法对累加器和数组的每个值(从左到右)应用函数以将其减少为单个值。

    来自Array.prototype.reduce() on MDN

    你可以这样使用这个函数:

    sumValues({a: 4, b: 6, c: -5, d: 0}); // gives 5
    

    请注意,此代码使用了一些旧版浏览器(如 IE)不支持的一些 ECMAScript 功能。您可能需要使用Babel 来编译您的代码。

    【讨论】:

    • 这需要你拉出一个 60K 的库 just 以拥有Object.values(),它将在除 Firefox 之外的每个浏览器上用 for 循环填充。即使没有 polyfill,对我来说,它也比常规的 for 循环慢 4 倍。
    • @Blender 如果您想使用 任何 的新 ECMAScript 功能并仍支持旧版浏览器,则无论如何都需要使用 Babel。此外,如果有人在 2 年后访问这个问题,现代浏览器可能会在那个时候实现Object.values()
    • 接受的答案有一个非常相似的方法,但传递给reduce 的函数似乎更简单一些。您是否故意省略了解析?
    • @Cerbrus 我假设该对象中的所有值都是数字。
    • @Blender 看来我是对的——一年半过去了,Object.values() is supported by all modern browsers
    【解决方案2】:

    你可以把它全部放在一个函数中:

    function sum( obj ) {
      var sum = 0;
      for( var el in obj ) {
        if( obj.hasOwnProperty( el ) ) {
          sum += parseFloat( obj[el] );
        }
      }
      return sum;
    }
        
    var sample = { a: 1 , b: 2 , c:3 };
    var summed = sum( sample );
    console.log( "sum: "+summed );


    为了好玩,这里是另一个使用Object.keys()Array.reduce() 的实现(浏览器支持应该不再是一个大问题了):

    function sum(obj) {
      return Object.keys(obj).reduce((sum,key)=>sum+parseFloat(obj[key]||0),0);
    }
    let sample = { a: 1 , b: 2 , c:3 };
    
    console.log(`sum:${sum(sample)}`);

    但这似乎要慢得多:jsperf.com

    【讨论】:

    • return sum + parseFloat( obj[key] || 0) 检查 false 或 null /blank 值
    • 很好地突出了解决方案之间的性能差异。虽然Object.keys().reduce 看起来更加优雅,但速度却慢了 60%。
    • niiiiiiiiceeeeeee
    【解决方案3】:

    如果你使用 lodash,你可以做类似的事情

    _.sum(_.values({ 'a': 1 , 'b': 2 , 'c':3 })) 
    

    【讨论】:

    • 我认为 JS 将值视为字符串。所以答案应该是“123”而不是“6”。如果我错了,请纠正我。
    【解决方案4】:

    常规的for 循环非常简洁:

    var total = 0;
    
    for (var property in object) {
        total += object[property];
    }
    

    如果您修改了原型,您可能需要添加 object.hasOwnProperty

    【讨论】:

      【解决方案5】:

      现在你可以利用reduce函数得到总和。

      const object1 = { 'a': 1 , 'b': 2 , 'c':3 }
      
      console.log(Object.values(object1).reduce((a, b) => a + b, 0));

      【讨论】:

        【解决方案6】:

        老实说,鉴于我们的“现代”,我会尽可能采用函数式编程方法,如下所示:

        const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);
        

        我们的累加器acc,从 0 开始,正在累加我们对象的所有循环值。这具有不依赖于任何内部或外部变量的额外好处;它是一个常量函数,所以它不会被意外覆盖...为 ES2015 赢得胜利!

        【讨论】:

          【解决方案7】:

          您不只是使用简单的for...in 循环有什么原因吗?

          var sample = { a: 1 , b: 2 , c:3 };
          var summed = 0;
          
          for (var key in sample) {
              summed += sample[key];
          };
          

          http://jsfiddle.net/vZhXs/

          【讨论】:

            【解决方案8】:

            let prices = {
              "apple": 100,
              "banana": 300,
              "orange": 250
            };
            
            let sum = 0;
            for (let price of Object.values(prices)) {
              sum += price;
            }
            
            alert(sum)

            【讨论】:

              【解决方案9】:

              我有点迟到了,但是,如果您需要更强大和灵活的解决方案,那么这是我的贡献。如果您只想对嵌套对象/数组组合中的特定属性求和,以及执行其他聚合方法,那么这是我在 React 项目中使用的一个小函数:

              var aggregateProperty = function(obj, property, aggregate, shallow, depth) {
                  //return aggregated value of a specific property within an object (or array of objects..)
              
                  if ((typeof obj !== 'object' && typeof obj !== 'array') || !property) {
                      return;
                  }
              
                  obj = JSON.parse(JSON.stringify(obj)); //an ugly way of copying the data object instead of pointing to its reference (so the original data remains unaffected)
                  const validAggregates = [ 'sum', 'min', 'max', 'count' ];
                  aggregate = (validAggregates.indexOf(aggregate.toLowerCase()) !== -1 ? aggregate.toLowerCase() : 'sum'); //default to sum
              
                  //default to false (if true, only searches (n) levels deep ignoring deeply nested data)
                  if (shallow === true) {
                      shallow = 2;
                  } else if (isNaN(shallow) || shallow < 2) {
                      shallow = false;
                  }
              
                  if (isNaN(depth)) {
                      depth = 1; //how far down the rabbit hole have we travelled?
                  }
              
                  var value = ((aggregate == 'min' || aggregate == 'max') ? null : 0);
                  for (var prop in obj) {
                      if (!obj.hasOwnProperty(prop)) {
                          continue;
                      }
              
                      var propValue = obj[prop];
                      var nested = (typeof propValue === 'object' || typeof propValue === 'array');
                      if (nested) {
                          //the property is an object or an array
              
                          if (prop == property && aggregate == 'count') {
                              value++;
                          }
              
                          if (shallow === false || depth < shallow) {
                              propValue = aggregateProperty(propValue, property, aggregate, shallow, depth+1); //recursively aggregate nested objects and arrays
                          } else {
                              continue; //skip this property
                          }
                      }
              
                      //aggregate the properties value based on the selected aggregation method
                      if ((prop == property || nested) && propValue) {
                          switch(aggregate) {
                              case 'sum':
                                  if (!isNaN(propValue)) {
                                      value += propValue;
                                  }
                                  break;
                              case 'min':
                                  if ((propValue < value) || !value) {
                                      value = propValue;
                                  }
                                  break;
                              case 'max':
                                  if ((propValue > value) || !value) {
                                      value = propValue;
                                  }
                                  break;
                              case 'count':
                                  if (propValue) {
                                      if (nested) {
                                          value += propValue;
                                      } else {
                                          value++;
                                      }
                                  }
                                  break;
                          }
                      }
                  }
              
                  return value;
              }
              

              它是递归的,非 ES6,它应该可以在大多数半现代浏览器中工作。你可以这样使用它:

              const onlineCount = aggregateProperty(this.props.contacts, 'online', 'count');
              

              参数分解:

              obj = 对象或数组
              属性 = 您希望对其执行聚合方法的嵌套对象/数组中的属性
              aggregate = 聚合方法(sum、min、max 或 count)
              shallow = 可以设置为 true/false 或数值
              depth = 应为空或未定义(用于跟踪后续的递归回调)

              如果您知道不需要搜索深度嵌套的数据,则可以使用 Shallow 来提高性能。例如,如果您有以下数组:

              [
                  {
                      id: 1,
                      otherData: { ... },
                      valueToBeTotaled: ?
                  },
                  {
                      id: 2,
                      otherData: { ... },
                      valueToBeTotaled: ?
                  },
                  {
                      id: 3,
                      otherData: { ... },
                      valueToBeTotaled: ?
                  },
                  ...
              ]
              

              如果您想避免循环遍历 otherData 属性,因为您要聚合的值没有嵌套那么深,您可以将 shallow 设置为 true。

              【讨论】:

                【解决方案10】:

                使用 Lodash

                 import _ from 'Lodash';
                 
                 var object_array = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}];
                 
                 return _.sumBy(object_array, 'c')
                 
                 // return => 9

                【讨论】:

                  【解决方案11】:

                  我在尝试解决类似问题时从@jbabey 那里发现了这个解决方案。稍加修改,我就做对了。在我的例子中,对象键是数字(489)和字符串(“489”)。因此,为了解决这个问题,每个键都被解析。以下代码有效:

                  var array = {"nR": 22, "nH": 7, "totB": "2761", "nSR": 16, "htRb": "91981"}
                  var parskey = 0;
                  for (var key in array) {
                      parskey = parseInt(array[key]);
                      sum += parskey;
                  };
                  return(sum);
                  

                  【讨论】:

                    【解决方案12】:

                    一个ramda一个班轮:

                    import {
                     compose, 
                     sum,
                     values,
                    } from 'ramda'
                    
                    export const sumValues = compose(sum, values);
                    

                    使用: const summed = sumValues({ 'a': 1 , 'b': 2 , 'c':3 });

                    【讨论】:

                      【解决方案13】:

                      我们可以使用 in 关键字迭代对象,并且可以执行任何算术运算。

                      // input
                      const sample = {
                          'a': 1,
                          'b': 2,
                          'c': 3
                      };
                      
                      // var
                      let sum = 0;
                      
                      // object iteration
                      for (key in sample) {
                          //sum
                          sum += (+sample[key]);
                      }
                      // result
                      console.log("sum:=>", sum);

                      【讨论】:

                        【解决方案14】:

                        通过解析Integer对对象键值求和。将字符串格式转换为整数并对值求和

                        var obj = {
                          pay: 22
                        };
                        obj.pay;
                        console.log(obj.pay);
                        var x = parseInt(obj.pay);
                        console.log(x + 20);

                        【讨论】:

                          【解决方案15】:

                          一个简单的解决方案是使用 for..in 循环来求和。

                          function findSum(obj){
                            let sum = 0;
                            for(property in obj){
                              sum += obj[property];
                            }
                            return sum;
                          }
                          
                          
                          var sample = { a: 1 , b: 2 , c:3 };
                          console.log(findSum(sample));
                          

                          【讨论】:

                            猜你喜欢
                            • 2023-03-22
                            • 2023-02-02
                            • 2016-11-27
                            • 2020-12-29
                            • 2018-06-22
                            • 2020-08-23
                            • 1970-01-01
                            • 1970-01-01
                            • 2022-12-08
                            相关资源
                            最近更新 更多