web-dev-qa-db-ja.com

配列内のプロパティ値を合計するより良い方法

私はこのようなものを持っています:

$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;
}

配列が1つしかない場合は簡単ですが、合計したい別のプロパティ名を持つ他の配列があります。

私はこのような何かをすることができれば私は幸せになるだろう:

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

しかし、私はこれを将来どのように再利用できるようにするかを知りません:

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

回答

@ gruff-bunnyの提案を使用することにしたので、 ネイティブオブジェクトのプロトタイピングを避ける (配列)

私は彼の答えを少し修正して配列を検証し、合計する値が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);
};
109
nramirez

更新された回答

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/

69
bottens

私はこの質問に受け入れられた答えがあることを知っていますが、 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');

Fiddle

191
Gruff Bunny

別の見方をすれば、これはnative JavaScript関数MapおよびReduceが構築されたものです(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.
80
SoEzPz

私は常にプロトタイプのメソッドを変更したりライブラリを追加したりしないようにしているので、これが私の解決策です。

Reduce Arrayプロトタイプメソッドを使用すれば十分です。

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

私はこれに2セントを落とすと思った:これは、外部変数に依存せず、常に純粋に機能的でなければならない操作の1つです。いくつかはすでに良い答えを出しており、reduceを使用することがここに行く方法です。

私たちのほとんどはすでにES2015構文を使用する余裕があるので、私の提案は次のとおりです。

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

私たちはそれを不変の関数にしています。ここでreduceが行っていることは、これだけです。アキュムレータの0の値で開始し、現在のループされたアイテムの値をそれに追加します。

関数型プログラミングとES2015に賛成です! :)

18

次のことができます。

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

これがまだ言及されているかどうかはわかりません。しかし、そのための lodash 関数があります。値が合計する属性である以下のスニペットは「値」です。

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

両方とも機能します。

4
Liam Middleton

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
Steve Breese

読みやすさを改善し、MapおよびReduceを使用する代替手段:

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);
1
codingbamby

Array.prototype.forEach() を使用することもできます

let totalAmount = 0;
$scope.traveler.forEach( data => totalAmount = totalAmount + data.Amount);
return totalAmount;
1
akhouri

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
kvimalkr55

私はすでにjqueryを使用していました。しかし、私はそれだけで十分に直感的だと思います:

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

これは基本的に@akhouriの回答の簡略版です。

0
SpiRail

これは私がより柔軟だと思う解決策です:

function sumOfArrayWithParameter (array, parameter) {
  let sum = null;
  if (array && array.length > 0 && typeof parameter === 'string') {
    sum = 0;
    for (let e of array) if (e && e.hasOwnProperty(parameter)) sum += e[parameter];
  }
  return sum;
}

合計を取得するには、次のように使用します。

let sum = sumOfArrayWithParameter(someArray, 'someProperty');
0
Philippe Genois