If you have an array of objects like so:
What's the best way to add all numerical values in each object so each one looks something like this:
{category: "A", total: 44}
So in the 0th item in the original array, 0 23 21 is 24, and is now represented by the new 'total' key.
Bearing in mind that the 'keys' with numerical values in the original array e.g. 'col2' are randomly generated (so another array like the original can have keys like 'somethingelse'.
I've attempted it with the following, but I believe it's not written correctly:
newArrayOfObjects.forEach(element => {
Object.values(element).reduce((a, b) => a b);
});
It may be good to know but the 'key' category always exists in each object and is fixed. All other key values are numerical and there'll always be more than one.
CodePudding user response:
Please check this.
const array = [
{
category: 'A',
col1: 1,
col2: 2,
col3: 3,
},
{
category: 'B',
col1: 2,
col2: 3,
col3: 4,
}
]
const result = array.map(obj => {
const total = Object.values(obj).reduce((acc, value) => {
if (typeof value === 'number') {
return acc value;
}
return acc;
}, 0)
return {
category: obj.category,
total
}
})
console.log(result)
CodePudding user response:
You could use Array.map()
along with Array.reduce()
to sum the numeric values in the array.
We'd create a toNumber()
function to get the numeric value of any property. If this is not a number, it will return 0 (keeping the total unchanged).
let arr = [
{ a: 0, category: "a", col2: 23, col3: 21 },
{ b: 0, category: "b", x: 100, y: 10, z: 1 },
{ j: 0, category: "x", foo: 25, bar: 50, meta: 'content' },
]
function toNumber(n) {
return isNaN(n) ? 0: n;
}
function sumTotals(a) {
return a.map(({ category, ...obj}) => {
const total = Object.values(obj).reduce((total, value) => {
return total toNumber(value);
}, 0);
return { category, total };
})
}
console.log('Totals:', sumTotals(arr))
.as-console-wrapper { max-height: 100% !important; }
CodePudding user response:
arr = [{x:1}, {x:3}]
arr.reduce((accumulator, current) => accumulator current.x, 0);
CodePudding user response:
var data = [
{ "category": "A", "col0": 5, "col1": 8, "some": "thing"},
{ "category": "B", "col1": 3, "col2": 5}
];
var res = data.map((it) => {
const { category, ...rest } = it;
return {
...it,
total: Object.values(rest).reduce(
(prev, curr) =>
typeof curr === "number" ? prev curr : prev, // add if the current value is numeric
0
)
}
});
console.log(res);
/**
[
{"category":"A","col0":5,"col1":8,"some":"tst","total":13},
{"category":"B","col1":3,"col2":5,"total":8}
]
**/
CodePudding user response:
I think you are on the right way, you just need to do a bit more destructuring and type checking:
const aggregated = newArrayOfObjects.map((obj) =>
Object.entries(obj).reduce(
(newObj, [key, value]) => ({
...newObj,
...(typeof value === "number"
? { total: newObj.total value }
: { [key]: value }),
}),
{ total: 0 }
)
);
First, you map all objects to their representations as key-value-pairs. Then you iterate over these key-value pairs and keep all non-numerical values and their respective keys, while dropping key-value-pairs with a numerical value and replacing them by a property in which you aggregate the total value.
CodePudding user response:
Solution with reduce in O(n) complexity. (didn't add type checks for corner cases)
const result = newArrayOfObjects.reduce((prevResult, curItem) => {
if (prevResult) {
prevResult.push({
category: curItem.category,
total: curItem.col2 curItem.col3
});
}
return prevResult;
}, []);