배열에서 속성 값을 합산하는 더 좋은 방법


184

나는 이와 같은 것을 가지고있다 :

$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 제안을 사용하기로 결정 했으므로 원시 객체 (배열)의 프로토 타이핑을 피하십시오

방금 배열의 유효성을 검사하는 그의 답변을 약간 수정했으며 합계 값이 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);
};

2
당신은 게시 할 수 있습니다 응답을 int로서 대답 .
— Ken Kin

답변:


124

업데이트 된 답변

배열 프로토 타입에 함수를 추가하는 모든 단점으로 인해이 질문에 원래 요청 된 구문과 구문을 유지하는 대안을 제공하기 위해이 답변을 업데이트하고 있습니다.

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

원래 답변

배열이므로 배열 프로토 타입에 함수를 추가 할 수 있습니다.

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
고맙습니다 @ sp00m 이제 gruff-bunny가 대답 한 것처럼 array.reduce로 구현을 변경했습니다.
— nramirez

이전 브라우저를 지원해야하는 경우 reduce 기능을 polyfill해야합니다. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
— bottens

Array.prototype나중에 코드가 손상 될 수 있으므로 확장하지 마십시오 . 기본 객체를 확장하는 것이 왜 나쁜 습관입니까? .
— str

@bottens 배열에 null 객체가 있으면 어떻게해야합니까?
— Obby

228

나는이 질문에 대한 대답이 허용된다는 것을 알고 있지만 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


훌륭한 답변, $scope.travelerTotal = $scope.sum($scope.traveler, 'Amount');컨트롤러 기능의 시작 부분에 넣을 수 있습니까?
— Mo.

합계 기능을 만든 후에 오는 경우 예입니다.
— Gruff Bunny

14
2015 년 10 월 6 일에 공감 비가 발생하는 이유는 무엇입니까? 답변에 문제가있는 경우 의견을 추가하면 수정하겠습니다. 익명의 다운 보트를 배우는 사람은 없습니다.
— Gruff Bunny

prop이 배열의 객체 중 하나에 존재하지 않으면 NaN이 발생할 수 있습니다. 이것이 최선의 검사인지는 모르겠지만 제 경우에는 효과가있었습니다 : function (items, prop) {return items.reduce (function (a, b) {if (! isNaN (b [prop])) { return a + b [prop];} else {return a}}, 0); }
— claytronicon

130

또 다른 특징은 nativeJavaScript 기능 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.

4
return Number(item.Amount);숫자 만 확인하기
— diEcho

4
prevreduce 함수에서 변수의 이름으로 만 논쟁 합니다. 나에게 그것은 배열에서 이전 값을 얻고 있음을 의미합니다. 그러나 실제로 이전의 모든 값이 줄어 듭니다. 나는 accumulator, aggregator또는 sumSoFar명확성을 위해 좋아 한다.
— carpiediem

93

나는 항상 프로토 타입 방법을 변경하고 라이브러리를 추가하는 것을 피하므로 이것이 내 솔루션입니다.

배열 프로토 타입 축소 방법을 사용하면 충분합니다

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

3
두 번째 매개 변수 (의 초기 값을 결정 a)는 reduce객체와 함께 사용할 때 트릭 을 수행합니다. 첫 번째 반복에서는 배열 a의 첫 번째 객체가 아니며 items대신됩니다 0.
— Parziphal

기능으로 : const sumBy = (items, prop) => items.reduce((a, b) => +a + +b[prop], 0); 사용법 :sumBy(traveler, 'Amount') // => 235
— Rafi

2
올드 스쿨 프로그래머로서 reduce구문은 완전히 둔해 보입니다. 내 뇌는 여전히 "기본적으로"이 더 나은 이해 :let total = 0; items.forEach((item) => { total += item.price; });
— AndrWeisR

1
@AndrWeisR 귀하의 솔루션이 가장 좋습니다. 또한 네이티브의 사용은 그것이 의미하는 바를 거의 설명하지 못하는 버즈 워드이므로 사용합니다. 귀하의 솔루션을 기반으로 훨씬 더 기본적인 코드 라인을 만들었으며 훌륭하게 작동했습니다. let total = 0; items.forEach(item => total += item.price)
— Ian Poston Framer

22

나는 이것에 내 2 센트를 떨어 뜨릴 것이라고 생각했다 : 이것은 외부 변수에 의존하지 않고 항상 순수하게 기능 해야하는 작업 중 하나입니다. 몇 사람은 이미 좋은 대답을했으며 사용 reduce방법은 여기입니다.

우리 대부분은 이미 ES2015 구문을 사용할 여유가 있으므로 제 제안은 다음과 같습니다.

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

우리가있는 동안 우리는 그것을 불변 함수로 만들고 있습니다. 어떤 reduce값으로 시작 : 여기서하고있는 것은 단순히 이것이다 0누산기에 대한, 그리고 현재 루프 항목의 값을 추가합니다.

기능 프로그래밍과 ES2015를위한 예! :)


22

향상된 가독성과 사용에 대한 대안 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"
— Mayank Pandeyz

.reduce(*** => *** + ***, 0);다른 사람이 "+1"을
— 생략 한

19

다음을 수행 할 수 있습니다.

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

13

그것은 나를 위해에서 일하고 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);

도움이 되길 바랍니다.


4

이것이 아직 언급되지 않았습니다. 그러나 그것에 대한 lodash 기능이 있습니다. 값이 합산 할 속성 아래의 스 니펫은 'value'입니다.

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

둘 다 작동합니다.



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))
`


1

객체 배열에서

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

0

이미 jquery를 사용하고있었습니다. 그러나 나는 그것의 직관적 인 것만으로 충분하다고 생각합니다.

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

이것은 기본적으로 @akhouri의 대답의 짧은 버전입니다.


0

더 유연한 솔루션은 다음과 같습니다.

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');
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.