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


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 기능 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.

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

향상된 가독성과 사용에 대한 대안 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);

완벽한 친구, "+1"
Mayank Pandeyz

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

19

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

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

13

그것은 나를 위해에서 일하고 TypeScriptJavaScript:

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.