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: https://stackoverflow.com/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!

5 Answers 5

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

Sign up to request clarification or add additional context in comments.

Comments

2

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

Comments

1

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

1 Comment

Reduce removes the need to assign an object and then run values - you are still looping twice, but I removed the downvote
1

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

Comments

0

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.