简体   繁体   中英

JavaScript - Sum the values of same ids of different objects in the array of objects

I have an array of objects in my code. The objects are having same keys with different or same values.

        var a = [];
        a.push({taxid : 1, tax_name: 'VAT', tax_value:'25.00'});
        a.push({taxid : 2, tax_name: 'Service Tax', tax_value:'20.00'});
        a.push({taxid : 1, tax_name: 'VAT', tax_value:'25.00'});
        a.push({taxid : 2, tax_name: 'Service Tax', tax_value:'75.00'});
        console.log(a);

The array Looks like below:

在此处输入图片说明

I want to iterate through this array and if the taxid is the same in the objects, then the tax_value should be summed up.

I tried using two for loops and it's working but in that case, it is checking the id with itself and summing up the value with itself. Like below:

var sum = 0;
var newArray = [];
for (var i=0; i<a.length;i++){
    for (var j=0;j<a.length;j++){
        if(a[i]['taxid']==a[j]['taxid']){
            sum = a[i]['tax_value'] + a[j]['tax_value'];
        }
    }
    newArray.push({taxid : a[i]['taxid'], tax_value : sum});
}

I appreciate your concerns, Thank You.

you can achive this in different ways.

One ay is to use reduce:

a = a.reduce((c, i)=>{c[i.taxid]=(c[i.taxid]||0)+parseFloat(i.tax_value); return c}, {});

is this is too complecated for you, you can use a loop:

var t = {};
a.forEach((v)=>t[v.taxid]=(t[v.taxid]||0)+parseFloat(v.tax_value));
a = t;

of if the expression is too complecated, you can achive this with a simple if condition:

var t = {};
a.forEach((v)=>{
  if(t[v.taxid])
    t[v.taxid]+=parseFloat(v.tax_value);
  else
    t[v.taxid] = parseFloat(v.tax_value);
});
a = t;

EDIT: In response to the edit of the question and the volitionaly output: [{taxid : NUM, tax_value : NUM}, ...]

a = a.reduce((c, i)=>{
  let cc = c.findIndex((e)=>e.taxid==i.taxid);
  if(cc==-1) c.push({taxid: i.taxid, tax_value: parseFloat(i.tax_value)});
  else c[cc].tax_value += parseFloat(i.tax_value)
  return c
}, []);

You can just use reduce and sum the values together

 var a = []; a.push({taxid : 1, tax_name: 'VAT', tax_value:'25.00'}); a.push({taxid : 2, tax_name: 'Service Tax', tax_value:'20.00'}); a.push({taxid : 1, tax_name: 'VAT', tax_value:'25.00'}); a.push({taxid : 2, tax_name: 'Service Tax', tax_value:'75.00'}); let res = a.reduce((a, b) => a.set(b.taxid, (a.get(b.taxid) || 0) + Number(b.tax_value)), new Map); console.log(res);

If you want to get the resulting Map to an object, you can use

toObject(map) {
    let obj = Object.create(null);
    for (let [key, value] of map.entries()) {
        obj[key] = value;
    }
    return obj;
} 

console.log(toObject(res));
var output = a.reduce( (final,data) => {
 let isAlready = final.find( ( value ) => { 
   value.taxid == data.taxid;
 });
 if(!isAlready){
   final.push( data );
 } else {
   var index = final.indexOf(isAlready);
   final[index].tax_value = parseFloat(final[index].tax_value) + parseFloat(data.tax_value);
 }
 return final;
},[] )

Some considerations:

  • tax_value is a string. You need at least an implicit type casting to number, because if you add a number and a string, the number gets converted to string and you get a string concatination, but not an arithmetic operation.

  • Mutate the given data structure or create a new one. In this case and usually always, it is better to generate a new result set instead of using the given structure as data and as result set. This may lead to confusion, because some code may relay on unchanged structures.

Solution

  • Using a hash table, which might be a Map on newer systems (ES6) or an object for keeping reference to the same object with the same taxid .

  • Using an implicid conversion to number with an unary plus + .

  • Using a single loop.

 var data = [{ taxid: 1, tax_name: 'VAT', tax_value:' 25.00' }, { taxid: 2, tax_name: 'Service Tax', tax_value: '20.00' }, { taxid: 1, tax_name: 'VAT', tax_value: '25.00' }, { taxid: 2, tax_name: 'Service Tax', tax_value: '75.00' }], hash = Object.create(null), result = []; data.forEach(function (o) { if (!hash[o.taxid]) { hash[o.taxid] = { taxid: o.taxid, tax_name: o.tax_name, tax_value: 0 }; result.push(hash[o.taxid]); } hash[o.taxid].tax_value += +o.tax_value; }); console.log(result);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

**You can do it using forEach loop by creating empty object and start initializing it in each iteration it will check for the taxid if found then it will add to it otherwise it will go to else **

 const a = []; a.push({taxid : 1, tax_name: 'VAT', tax_value:'25.00'}); a.push({taxid : 2, tax_name: 'Service Tax', tax_value:'20.00'}); a.push({taxid : 1, tax_name: 'VAT', tax_value:'25.00'}); a.push({taxid : 2, tax_name: 'Service Tax', tax_value:'7.00'}); a.push({taxid : 3, tax_name: 'Service Tax', tax_value:'3.00'}); let holders={}; a.forEach(function (item) { if (holders.hasOwnProperty(item.taxid)) { holders[item.taxid] = holders[item.taxid] + parseFloat(item.tax_value); } else { holders[item.taxid] = parseFloat(item.tax_value); } }); console.log(holders);

I think you want something like this as your implementation.

 var a = []; a.push({taxid : 1, tax_name: 'VAT', tax_value:'25.00'}); a.push({taxid : 2, tax_name: 'Service Tax', tax_value:'20.00'}); a.push({taxid : 1, tax_name: 'VAT', tax_value:'25.00'}); a.push({taxid : 2, tax_name: 'Service Tax', tax_value:'75.00'}); //Sum up all the same taxid tax_value var temp = {}; a.forEach(function(obj){ if(!temp[obj.taxid]){ temp[obj.taxid] = obj.tax_value; } else { temp[obj.taxid] = Number(temp[obj.taxid]) + Number(obj.tax_value); } }); //Format the data into desired output var result = []; for(var key in temp){ result.push({ taxid: key, tax_value: temp[key] }) } console.log(result)

just add another condition to your loop ("if" statement in second loop)

(a[i]['taxid'] === a[j]['taxid'] && j !== i)

explanation
as you said, loop is checking the id with itself, to prevent this you can add "j !== i" so if second loop hits id from first loop it will pass over it so it will not sum itself

This is a possible solution. It involves changing the sum to an object, hence the var sum = {} , and then adding the total of tax_value to any ids that match the other object. I've tried to use your original code, but keep in mind there are more efficient solutions.

PS: the a[i] !== a[j] in the if statement prevents it from checking the 'taxid' with itself

 var a = []; a.push({taxid : 1, tax_name: 'VAT', tax_value:'25.00'}); a.push({taxid : 2, tax_name: 'Service Tax', tax_value:'20.00'}); a.push({taxid : 1, tax_name: 'VAT', tax_value:'25.00'}); a.push({taxid : 2, tax_name: 'Service Tax', tax_value:'75.00'}); var sum = {}; var res = 0; var newArray = []; for (var i=0; i<a.length;i++){ for (var j=0;j<a.length;j++){ if(a[i]['taxid']==a[j]['taxid'] && a[i] !== a[j]){ sum[a[i]['taxid']] === undefined ? sum[a[i]['taxid']] = 0 : sum[a[i]['taxid']] += parseFloat(a[i]['tax_value']) + parseFloat(a[j]['tax_value']); } } } console.log(sum);

Cake

 const a = []; a.push({taxid : 1, tax_name: 'VAT', tax_value:'25.00'}); a.push({taxid : 2, tax_name: 'Service Tax', tax_value:'20.00'}); a.push({taxid : 1, tax_name: 'VAT', tax_value:'25.00'}); a.push({taxid : 2, tax_name: 'Service Tax', tax_value:'75.00'}); const sum = {}; for (var i = 0; i < a.length; i++) { const o = a[i]; const lol = parseFloat(o.tax_value); sum[o.taxid] = (sum[o.taxid]) ? sum[o.taxid] + lol : lol; } console.log(sum);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM