最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Sum values for multiple objects in the array - Stack Overflow

programmeradmin2浏览0评论

This is what I have:

const arrayA = [{name:'a', amount: 10, serviceId: '23a', test:'SUCCESS'},
                {name:'a', amount: 9, test:'FAIL'}, 
                {name:'b', amount: 15, serviceId: '23b', test:'SUCCESS'}]

 

(note that there's object not having 'serviceId')

I would like to get:

 [{name:'a', amount: 19, test:'FAIL'},
  {name:'b', amount: 15, test:'SUCCESS'}]
  • I want to sum amount field grouped by name.
  • 'test' field should be FAIL if there's any object with the value FAIL (grouped by name)
  • I don't care about the value of serviceId and don't want to include it in the new object.

I have searched, and tried something like this: (reference: )

const result = Object.values(arrayA.reduce((r, o) => (r[o.name]
  ? (r[o.name].amount += o.amount)
  : (r[o.name] = {...o}), r), {}));

but still not sure how to assign test field.

Any help would be appreciated!

This is what I have:

const arrayA = [{name:'a', amount: 10, serviceId: '23a', test:'SUCCESS'},
                {name:'a', amount: 9, test:'FAIL'}, 
                {name:'b', amount: 15, serviceId: '23b', test:'SUCCESS'}]

 

(note that there's object not having 'serviceId')

I would like to get:

 [{name:'a', amount: 19, test:'FAIL'},
  {name:'b', amount: 15, test:'SUCCESS'}]
  • I want to sum amount field grouped by name.
  • 'test' field should be FAIL if there's any object with the value FAIL (grouped by name)
  • I don't care about the value of serviceId and don't want to include it in the new object.

I have searched, and tried something like this: (reference: https://stackoverflow./a/50338360/13840216)

const result = Object.values(arrayA.reduce((r, o) => (r[o.name]
  ? (r[o.name].amount += o.amount)
  : (r[o.name] = {...o}), r), {}));

but still not sure how to assign test field.

Any help would be appreciated!

Share Improve this question edited Dec 3, 2020 at 9:15 tadman 212k23 gold badges236 silver badges265 bronze badges asked Dec 3, 2020 at 9:15 amu03amu03 3813 silver badges19 bronze badges
Add a ment  | 

5 Answers 5

Reset to default 5

You need to check test and update the value, if necessary.

const
    array = [{ name: 'a', amount: 10, serviceId: '23a', test: 'SUCCESS' }, { name: 'a', amount: 9, test: 'FAIL' }, { name: 'b', amount: 15, serviceId: '23b', test: 'SUCCESS' }],
    result = Object.values(array.reduce((r, { name, amount, test }) => {
        if (!r[name]) r[name] = { name, amount: 0, test };
        r[name].amount += amount;
        if (test === 'FAIL') r[name].test = 'FAIL';
        return r;
    }, {}));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

This? Just test if the .test is already fail

const arrayA = [{ name: 'a', amount: 10, serviceId: '23a', test: 'SUCCESS' }, { name: 'a', amount: 9, test: 'FAIL' }, { name: 'b', amount: 15, serviceId: '23b', test: 'SUCCESS' }],
  result = Object.values(
    arrayA.reduce((r, o) => {
      r[o.name] ? (r[o.name].amount += o.amount) : (r[o.name] = { ...o })
      r[o.name].test = r[o.name].test === "FAIL" ? "FAIL" : o.test;
      return r;
    }, {})
  );

console.log(result);

Store the sums and final values in an object and then convert them into an array.

const arrayA = [
  { name: "a", amount: 10, serviceId: "23a", test: "SUCCESS" },
  { name: "a", amount: 9, test: "FAIL" },
  { name: "b", amount: 15, serviceId: "23b", test: "SUCCESS" },
];

const map = {};

arrayA.forEach((row) => {
  if (!map[row.name]) {
    map[row.name] = { name: row.name, amount: 0, test: "SUCCESS" };
  }

  map[row.name].amount += row.amount;

  if (row.test === "FAIL") {
    map[row.name].test = "FAIL";
  }
});

const result = Object.values(map);

console.log(result);

That is a nice use case of how to process data in js, particularly how functions like map and reduce can help you do that processing. Which are a nice alternative to loops and iterations.

Moreover, I'd advise you to do the processing in steps, as you have defined in the description. For example:

const arrayA = [
    {name:'a', amount: 10, serviceId: '23a', test:'SUCCESS'},
    {name:'a', amount: 9, test:'FAIL'},
    {name:'b', amount: 15, serviceId: '23b', test:'SUCCESS'}
]

// First group the items by name
const byName = arrayA.reduce((ob, item) => {
    if(!(item.name in  ob))
        ob[item.name] = []
    ob[item.name].push({amount: item.amount, test: item.test})
    return ob
}, {})

// Then pute the total amount in each group and find if there is any FAIL in a group
const sumByName = Object.keys(byName).map(name => { // This is a way to iterate through the groups
    // Sum the amount in all elements of a group
    const amount = byName[name].reduce((sum, item) => sum + item.amount , 0)
    // Find if there is any FAIL in a group
    const test = byName[name].map(item => item.test) // Get an array with only the test string
        .includes('FAIL') ? 'FAIL': 'SUCCESS' // Evaluate if the array includes FAIL
    return ({name, amount, test})
})

console.log(sumByName)

Finally, I'd advise you to watch these videos on map and reduce (and all the content of that channel for this matter)

  • Reduce
  • Map

you can use Array.reduce method:

const arrayA=[{name:"a",amount:10,serviceId:"23a",test:"SUCCESS"},{name:"a",amount:9,test:"FAIL"},{name:"b",amount:15,serviceId:"23b",test:"SUCCESS"}];

let result  = arrayA.reduce((aac,{name,amount,test}) => {
    let idx = aac.findIndex(n => n.name === name)
    if( idx != -1){
        aac[idx].amount += amount;
        if(test === "FAIL")
            aac[idx].test = "FAIL"        
        return aac
    }
    aac.push({name,amount,test})
    return aac
},[])

console.log(result);
console.log(arrayA)

发布评论

评论列表(0)

  1. 暂无评论