更好地计算数组中属性值的方法

问题描述 投票:108回答:12

我有这样的事情:

$scope.traveler = [
            {  description: 'Senior', Amount: 50},
            {  description: 'Senior', Amount: 50},
            {  description: 'Adult', Amount: 75},
            {  description: 'Child', Amount: 35},
            {  description: 'Infant', Amount: 25 },
];

现在有了这个数组的总量,我正在做这样的事情:

$scope.totalAmount = function(){
       var total = 0;
       for (var i = 0; i < $scope.traveler.length; i++) {
              total = total + $scope.traveler[i].Amount;
            }
       return total;
}

当只有一个数组时很容易,但我有其他数组,我想要总结一个不同的属性名称。

我会更高兴如果我可以做这样的事情:

$scope.traveler.Sum({ Amount });

但我不知道如何通过这种方式来解决这个问题,我可以在将来重复使用它,如下所示:

$scope.someArray.Sum({ someProperty });

回答

我决定使用@gruff-bunny建议,所以我avoid prototyping native object(数组)

我只是对他的答案做了一点修改,验证了数组,并且sum的值不为null,这是我的最终实现:

$scope.sum = function (items, prop) {
    if (items == null) {
        return 0;
    }
    return items.reduce(function (a, b) {
        return b[prop] == null ? a : a + b[prop];
    }, 0);
};
javascript arrays prototype-programming
12个回答
70
投票

更新的答案

由于向Array原型添加函数的所有缺点,我正在更新此答案以提供一种替代方法,使语法保持与问题中最初请求的语法类似。

class TravellerCollection extends Array {
    sum(key) {
        return this.reduce((a, b) => a + (b[key] || 0), 0);
    }
}
const traveler = new TravellerCollection(...[
    {  description: 'Senior', Amount: 50},
    {  description: 'Senior', Amount: 50},
    {  description: 'Adult', Amount: 75},
    {  description: 'Child', Amount: 35},
    {  description: 'Infant', Amount: 25 },
]);

console.log(traveler.sum('Amount')); //~> 235

原始答案

由于它是一个数组,您可以向Array原型添加一个函数。

traveler = [
    {  description: 'Senior', Amount: 50},
    {  description: 'Senior', Amount: 50},
    {  description: 'Adult', Amount: 75},
    {  description: 'Child', Amount: 35},
    {  description: 'Infant', Amount: 25 },
];

Array.prototype.sum = function (prop) {
    var total = 0
    for ( var i = 0, _len = this.length; i < _len; i++ ) {
        total += this[i][prop]
    }
    return total
}

console.log(traveler.sum("Amount"))

小提琴:http://jsfiddle.net/9BAmj/


1
投票

这是使用ES6箭头功能的单线程。

const sumPropertyValue = (items, prop) => items.reduce((a, b) => a + b[prop], 0);

// usage:
const cart_items = [ {quantity: 3}, {quantity: 4}, {quantity: 2} ];
const cart_total = sumPropertyValue(cart_items, 'quantity');

1
投票

如何使用Javascript对对象数组求和

const traveler = [
  {  description: 'Senior', Amount: 50},
  {  description: 'Senior', Amount: 50},
  {  description: 'Adult', Amount: 75},
  {  description: 'Child', Amount: 35},
  {  description: 'Infant', Amount: 25 }
];

const traveler = [
    {  description: 'Senior', Amount: 50},
    {  description: 'Senior', Amount: 50},
    {  description: 'Adult', Amount: 75},
    {  description: 'Child', Amount: 35},
    {  description: 'Infant', Amount: 25 },
];
function sum(arrayData, key){
   return arrayData.reduce((a,b) => {
  return {Amount : a.Amount + b.Amount}
})
}
console.log(sum(traveler))
`

0
投票

我已经在使用jquery了。但我觉得它足够直观,只有:

var total_amount = 0; 
$.each(traveler, function( i, v ) { total_amount += v.Amount ; });

这基本上只是@ akhouri答案的简写版本。


193
投票

我知道这个问题有一个公认的答案,但我认为我会使用array.reduce的替代方法,看到汇总数组是减少的规范示例:

$scope.sum = function(items, prop){
    return items.reduce( function(a, b){
        return a + b[prop];
    }, 0);
};

$scope.travelerTotal = $scope.sum($scope.traveler, 'Amount');

Fiddle


82
投票

这是另一种观点,这就是native JavaScript函数MapReduce的构建(Map和Reduce是许多语言中的强者)。

var traveler = [{description: 'Senior', Amount: 50},
                {description: 'Senior', Amount: 50},
                {description: 'Adult', Amount: 75},
                {description: 'Child', Amount: 35},
                {description: 'Infant', Amount: 25}];

function amount(item){
  return item.Amount;
}

function sum(prev, next){
  return prev + next;
}

traveler.map(amount).reduce(sum);
// => 235;

// or use arrow functions
traveler.map(item => item.Amount).reduce((prev, next) => prev + next);

注意:通过制作单独的较小函数,我们可以再次使用它们。

// Example of reuse.
// Get only Amounts greater than 0;

// Also, while using Javascript, stick with camelCase.
// If you do decide to go against the standards, 
// then maintain your decision with all keys as in...

// { description: 'Senior', Amount: 50 }

// would be

// { Description: 'Senior', Amount: 50 };

var travelers = [{description: 'Senior', amount: 50},
                {description: 'Senior', amount: 50},
                {description: 'Adult', amount: 75},
                {description: 'Child', amount: 35},
                {description: 'Infant', amount: 0 }];

// Directly above Travelers array I changed "Amount" to "amount" to match standards.

function amount(item){
  return item.amount;
}

travelers.filter(amount);
// => [{description: 'Senior', amount: 50},
//     {description: 'Senior', amount: 50},
//     {description: 'Adult', amount: 75},
//     {description: 'Child', amount: 35}];
//     Does not include "Infant" as 0 is falsey.

60
投票

我总是避免更改原型方法和添加库,所以这是我的解决方案:

使用reduce Array原型方法就足够了

// + operator for casting to Number
items.reduce((a, b) => +a + +b.price, 0);

18
投票

我以为我会把这两分钱放在这上面:这是其中一个应该始终纯粹功能的操作,而不是依赖于任何外部变量。一些已经给出了一个很好的答案,使用reduce是去这里的方式。

由于我们大多数人已经可以负担得起使用ES2015语法,所以这是我的主张:

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

我们正在努力使它成为一个不可改变的功能。 reduce在这里做的只是这样:从累加器的0值开始,并将当前循环项的值添加到它。

是的功能编程和ES2015! :)


13
投票

您可以执行以下操作:

$scope.traveler.map(o=>o.Amount).reduce((a,c)=>a+c);

5
投票

提高可读性和使用MapReduce的替代方案:

const traveler = [
    {  description: 'Senior', amount: 50 },
    {  description: 'Senior', amount: 50 },
    {  description: 'Adult', amount: 75 },
    {  description: 'Child', amount: 35 },
    {  description: 'Infant', amount: 25 },
];

const sum = traveler
  .map(item => item.amount)
  .reduce((prev, curr) => prev + curr, 0);

可重复使用的功能:

const calculateSum = (obj, field) => obj
  .map(items => items.attributes[field])
  .reduce((prev, curr) => prev + curr, 0);

4
投票

我不确定这是否已被提及。但是有一个lodash功能。下面的代码段是值,您的属性是“值”。

_.sumBy(objects, 'value');
_.sumBy(objects, function(o) { return o.value; });

两者都有效。


1
投票

也可以使用Array.prototype.forEach()

let totalAmount = 0;
$scope.traveler.forEach( data => totalAmount = totalAmount + data.Amount);
return totalAmount;
© www.soinside.com 2019 - 2024. All rights reserved.