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

nra*_*rez 136 javascript arrays prototype-programming

我有这样的事情:

$scope.traveler = [
            {  description: 'Senior', Amount: 50},
            {  description: 'Senior', Amount: 50},
            {  description: 'Adult', Amount: 75},
            {  description: 'Child', Amount: 35},
            {  description: 'Infant', Amount: 25 },
];
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

$scope.traveler.Sum({ Amount });
Run Code Online (Sandbox Code Playgroud)

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

$scope.someArray.Sum({ someProperty });
Run Code Online (Sandbox Code Playgroud)

回答

我决定使用@gruff-bunny建议,所以我避免原型对象(Array)的原型设计

我只是对他的答案做了一点修改,验证了数组,并且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);
};
Run Code Online (Sandbox Code Playgroud)

Gru*_*nny 201

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

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

$scope.travelerTotal = $scope.sum($scope.traveler, 'Amount');
Run Code Online (Sandbox Code Playgroud)

Fiddle

  • 2015年10月6日有什么理由进行投票?如果答案有问题,请添加评论,我会更正.没有人从匿名的downvotes中学到东西. (8认同)
  • 这是避免原生对象原型设计的好选择. (3认同)
  • 如果数组中的对象之一不存在(未定义)该 prop,则可能会导致 NaN。我不知道这是否是最好的检查,但它适用于我的情况: function(items, prop) { return items.reduce(function(a, b) { if (!isNaN(b[prop])) {返回 a + b[prop]; } else { 返回 a } }, 0); } (2认同)

SoE*_*zPz 93

只是另一种观点,这就是nativeJavaScript功能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);
Run Code Online (Sandbox Code Playgroud)

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

// 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.
Run Code Online (Sandbox Code Playgroud)

  • `return Number(item.Amount);`仅检查数字 (3认同)
  • 我只想在reduce函数中使用变量`prev`的名称。对我来说,这意味着您将在数组中获取先前的值。但这实际上是所有先前值的减少。为了清楚起见,我喜欢“累加器”,“聚合器”或“ sumSoFar”。 (3认同)

bot*_*ens 80

由于它是一个数组,您可以向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
Run Code Online (Sandbox Code Playgroud)

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


Pat*_*eib 69

使用 reduce 和解构求和 Amount:

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

console.log(traveler.reduce((n, {Amount}) => n + Amount, 0))
Run Code Online (Sandbox Code Playgroud)

  • 简单又容易,我选择的答案 (7认同)
  • 简单而强大的方法 - 应该是所有答案中最重要的。谢谢@帕特里克 (3认同)
  • 这应该是最佳答案 (2认同)

Eri*_*ino 68

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

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

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

  • 作为一个老派的程序员,“reduce”语法对我来说看起来很笨拙。我的大脑仍然“本​​机地”更好地理解这一点:`let total = 0; items.forEach((item) =&gt; { total += item.price; });` (6认同)
  • 当对象使用`reduce`时,第二个参数(确定`a`的初始值)起作用:在第一个iteratorion中,`a`将不是`items`数组的第一个对象,而是是'0`. (2认同)
  • @AndrWeisR 我最喜欢你的解决方案。还使用原生,因为它是一个流行词,很难解释它的含义。我根据您的解决方案编写了更基本的代码行,并且效果很好。`让总= 0; items.forEach(item =&gt; total += item.price)` (2认同)

Ric*_*ães 20

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

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

const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);
Run Code Online (Sandbox Code Playgroud)

我们正在努力使它成为一个不可改变的功能.什么reduce是做在这里很简单:先从值0的蓄电池,以及当前循环项的值添加到它.

是的功能编程和ES2015!:)


A.R*_*R.F 19

它对我有用,TypeScript并且JavaScript

let lst = [
     { description:'Senior', price: 10},
     { description:'Adult', price: 20},
     { description:'Child', price: 30}
];
let sum = lst.map(o => o.price).reduce((a, c) => { return a + c });
console.log(sum);
Run Code Online (Sandbox Code Playgroud)

我希望有用。


gre*_*nif 15

您可以执行以下操作:

$scope.traveler.map(o=>o.Amount).reduce((a,c)=>a+c);
Run Code Online (Sandbox Code Playgroud)


Lia*_*ton 12

我不确定这是否已经被提及。但是有一个lodash函数。下面的代码段,其中 value 是您对 sum 的属性是“值”。

_.sumBy(objects, 'value');
_.sumBy(objects, function(o) { return o.value; });
Run Code Online (Sandbox Code Playgroud)

两者都会起作用。


cod*_*mby 11

替代来提高可读性,并使用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);
Run Code Online (Sandbox Code Playgroud)

可重用功能:

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


akh*_*uri 6

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

let totalAmount = 0;
$scope.traveler.forEach( data => totalAmount = totalAmount + data.Amount);
return totalAmount;
Run Code Online (Sandbox Code Playgroud)


小智 6

来自对象数组

function getSum(array, column)
  let values = array.map((item) => parseInt(item[column]) || 0)
  return values.reduce((a, b) => a + b)
}

foo = [
  { a: 1, b: "" },
  { a: null, b: 2 },
  { a: 1, b: 2 },
  { a: 1, b: 2 },
]

getSum(foo, a) == 3
getSum(foo, b) == 6
Run Code Online (Sandbox Code Playgroud)


小智 5

您可以使用Array.prototype.reduce

const sum = traveler.reduce((acc , val)=>{
   return acc + val.amount;
} ,0);
Run Code Online (Sandbox Code Playgroud)