hope that you're doing well. I've a question related to the .reduce function. I'm refactoring an elder code and, in order to fulfill the DRY principle, I'd like to know how to create a function that allows my to achieve a 'simple' process from .reduce:
- Group the data by a certain key (
phoNumbId
in the example). - Sum values of another key (but related to the first key) to summarize both (this key is
mount
). - Return a dictionary with the grouped key and the added values
To clarify my question, I've this example dictionary:
const nexus = [
{ namesId: 1, phoNumbId: 1, country: 'PERU', mount: 1200 },
{ namesId: 1, phoNumbId: 2, country: 'CANADA', mount: 2000},
{ namesId: 2, phoNumbId: 2, country: 'ENGLAND', mount: 3000},
{ namesId: 2, phoNumbId: 3, country: 'RUSSIA', mount: 40000},
{ namesId: 3, phoNumbId: 1, country: 'BELGIUM', mount: 500},
{ namesId: 3, phoNumbId: 2, country: 'SPAIN', mount: 500},
{ namesId: 3, phoNumbId: 3, country: 'PORTUGAL', mount: 2020}
]
And the (coded) process that I want to refactor is:
var result2 = [];
nexus.reduce(function (res, value) {
if (!res[value.phoNumbId]) {
res[value.phoNumbId] = { phoNumbId: value.phoNumbId, mount: 0 };
result2.push(res[value.phoNumbId])
}
res[value.phoNumbId].mount = value.mount;
return res;
}, {});
The way that my limited knowledge in JS allows me to code a possible solution then is as follows:
function sumAll(firstValue,secondValue,finalArray){
if (!res[value.firstValue]) {
res[value.firstValue] = { firstValue: value.firstValue, secondValue: 0 };
finalArray.push(res[value.firstValue])
}
res[value.primerValor].secondValue = value.secondValue;
return res;
}
var result2 = [];
nexus.reduce(function (res, value) { sumAll(phoNumbId,mount,result2) }, {});
I'd really appreciate anykind of help :) P.S.: I couldn't think of another title for the question, feel that doesn't summarize the real problem. I accept suggestions.
CodePudding user response:
You can use computed property names - that's using your argument values in bracket notation - to create the object.
const data=[{namesId:1,phoNumbId:1,country:"PERU",mount:1200},{namesId:1,phoNumbId:2,country:"CANADA",mount:2e3},{namesId:2,phoNumbId:2,country:"ENGLAND",mount:3e3},{namesId:2,phoNumbId:3,country:"RUSSIA",mount:4e4},{namesId:3,phoNumbId:1,country:"BELGIUM",mount:500},{namesId:3,phoNumbId:2,country:"SPAIN",mount:500},{namesId:3,phoNumbId:3,country:"PORTUGAL",mount:2020}];
function sumAll(data, first, second) {
const temp = data.reduce((acc, c) => {
// For convenience assign the object key
// to the first argument
const key = c[first];
// If the key doesn't exist on the object
// add it and assign an object to it
acc[key] ??= { [first]: key, [second]: 0 };
// Then update the value
acc[key][second] = c[second];
return acc;
}, {});
// Finally you probably want to return
// an array of just those objects
return Object.values(temp);
}
console.log(sumAll(data, 'phoNumbId', 'mount'));
console.log(sumAll(data, 'namesId', 'mount'));
Additional documentation
CodePudding user response:
Consider your original code (before refactoring) is runnable.
Here is the first integration:
var result2 = nexus.reduce(function (res, value) {
if (!res[value.phoNumbId]) {
res[value.phoNumbId] = { phoNumbId: value.phoNumbId, mount: 0 };
res.push(res[value.phoNumbId])
}
res[value.phoNumbId].mount = value.mount;
return res;
}, []);
What changed:
- the return from the
reduce
function is assigned directly toresult2
- the 2nd param of the
reduce
function is the initial value of theresult2
from the origin (in this case, an empty array[]
) - the
result2.push(....)
is changed tores.push(....)
Here is the second integration:
var result = nexus.reduce(function (acc, cur, origin) {
if (!acc[cur.phoNumbId]) {
acc[cur.phoNumbId] = { phoNumbId: cur.phoNumbId, mount: 0 };
acc.push(acc[cur.phoNumbId])
}
acc[cur.phoNumbId].mount = cur.mount;
return acc;
}, []);
What changed:
- rename variables:
result2
->result
res
->acc
(it stands foraccumulator
)value
->cur
(it stands forcurrent value
)
- add new param:
origin
Here is the third integration
function my_reducer(acc, cur) {
if (!acc[cur.phoNumbId]) {
acc[cur.phoNumbId] = { phoNumbId: cur.phoNumbId, mount: 0 };
acc.push(acc[cur.phoNumbId])
}
acc[cur.phoNumbId].mount = cur.mount;
return acc;
}
var result = nexus.reduce(my_reducer, []);
What changed:
- Extract the
no name
function (the one that was passed as the 1st param to thereduce
function) to a function with a name.
It will take time to explain the way the reduce
function works. You can find out around the internet or other StackOverflow questions/answers.
Here is a short explanation:
Take a look at var result = nexus.reduce(my_reducer, []);
, consider
result
is an soup bow