Hey! This might be a stupid question but I don't know how to do it 'cause I'm a JS beginner. The motto of coding is DRY (don't repeat yourself) so I don't want to repeat myself.
Here's a short example that I made. I want to do sth like this with more objects (one, two, three, four ...) and not just these 3. So I would repeat myself very often with the calculations if I do it like the example. I've read you could do it with a for loop but I don't know how to do it so I ask you. I need every output that is in the comments. Hope it's easy to understand. :)
const coolObject = {
"one": {
"number1": 1,
"number2": 2
},
"two": {
"number1": 3,
"number2": 4
},
"three": {
"number1": 5,
"number2": 6
}
}
// first number of every object
const coolOne1 = coolObject.one.number1; // 1
const coolTwo1 = coolObject.two.number1; // 3
const coolThree1 = coolObject.three.number1; // 5
// sum of them
const coolSum1 = coolOne1 + coolTwo1 + coolThree1; // 9
// second number of every object
const coolOne2 = coolObject.one.number2; // 2
const coolTwo2 = coolObject.two.number2; // 4
const coolThree2 = coolObject.three.number2; // 6
// sum of them
const coolSum2 = coolOne2 + coolTwo2 + coolThree2; // 12
// sum of every object
const oneSum = coolOne1 + coolOne2; // 3
const twoSum = coolTwo1 + coolTwo2; // 7
const threeSum = coolThree1 + coolThree2; // 11
// sum of all
const total = coolSum1 + coolSum2; // 21
// OR
const total = oneSum + twoSum + threeSum; // 21
In my opinion, the common point here is:
Assume we need to build a "sum" method, it should:
sum(coolObject) // => 1 + 2 + 3 + 4 + 5 + 6
sum(coolObject.one) // => 1 + 2
Even deeper, for example with:
coolObject.four = {
number1: 8,
number2: {
number21: 7,
number22: {
number221: 9
}
}
}
sum(coolObject.four) // => 8 + 7 + 9
If you agree with my assumption, what you need may be a single method call that can sum all the values come from any level of the object property. I would like to recommend you to refer my solution as bellow:
let isArray = Array.isArray;
let makeArray = x => Array.from(Object.values(x));
let flatten = (arr) => {
return arr.reduce((prev, curr) => {
return prev.concat(isArray(curr) ? flatten(curr) : curr);
}, []);
};
let decay = (ob) => {
let arr = makeArray(ob);
if (arr.length > 0) {
return arr.map((item) => {
return decay(item);
});
}
return [ob];
};
let sum = (ob) => {
let arr = flatten(decay(ob));
return arr.reduce((prev, curr) => {
return prev + curr;
}, 0);
};
With a sum method like that, you can test:
const coolObject = {
one: {
number1: 1,
number2: 2
},
two: {
number1: 3,
number2: 4
},
three: {
number1: 5,
number2: 6
},
four: {
number1: 8,
number2: {
number21: 7,
number22: {
number221: 9
}
}
}
}
console.log(`sum(coolObject.one):`, sum(coolObject.one));
console.log(`sum(coolObject.two):`, sum(coolObject.two));
console.log(`sum(coolObject.three):`, sum(coolObject.three));
console.log(`sum(coolObject.four):`, sum(coolObject.four));
console.log(`sum(coolObject.four.number1):`, sum(coolObject.four.number1));
console.log(`sum(coolObject.four.number2):`, sum(coolObject.four.number2));
console.log(`sum(coolObject):`, sum(coolObject));
Refactoring the code
I guess, your goal is to get the total, so I will remove anything you don't need to that goal. Please tell me otherwise in a reply and I will update my answer :)
I will not go into detail how the loop works, because there are very good sites and tutorials for that (best one: MDN). Instead, I will show you step-by-step how I would improve the code.
You can get the total with any of the below code snippets for an undefined number of fields!
const coolObject = { "one": { "number1": 1, "number2": 2 }, "two": { "number1": 3, "number2": 4 }, "three": { "number1": 5, "number2": 6 } }0. (OPTIONAL) You don't have to use strings for field names (safing bytes) and in order to make the code more git-friendly, you should have a dangling comma after every field. Don't forget the semicolon at the end of the variable assignment!
const coolObject = { one: { number1: 1, number2: 2, }, two: { number1: 3, number2: 4, }, three: { number1: 5, number2: 6, }, };1. Using a for-loop:
let total = 0; // iterate over all fields of coolObject for (numberContainer in coolObject) { // iterate over all fields of the fields of coolObject for (number in coolObject[numberContainer]) { // add the number to the total total += coolObject[numberContainer][number]; } }2. Implement error handling:
let total = 0; // iterate over all fields of coolObject for (containerField in coolObject) { const numberContainer = coolObject[containerField]; // skip field if it is not an object if ( typeof numberContainer !== 'object' || !coolObject.hasOwnProperty(containerField) ) continue; // iterate over all fields of the fields of coolObject for (numberField in numberContainer) { const number = numberContainer[numberField]; // skip field if it is not a number if ( typeof number !== 'number' || !numberContainer.hasOwnProperty(numberField) ) continue; // add the number to the total total += number; } }3. Make total const:
const total = (() => { let tmp = 0; // iterate over all fields of coolObject for (containerField in coolObject) { const numberContainer = coolObject[containerField]; // skip field if it is not an object if ( typeof numberContainer !== 'object' || !coolObject.hasOwnProperty(containerField) ) continue; // iterate over all fields of the fields of coolObject for (numberField in numberContainer) { const number = numberContainer[numberField]; // skip field if it is not a number if ( typeof number !== 'number' || !numberContainer.hasOwnProperty(numberField) ) continue; // add the number to the total tmp += number; } } return tmp; })();4. (OPTIONAL) We could optimize the whole procedure and make it more functional, if we are able to change the coolObject to use Arrays instead of fields and Objects:
const coolArray = [ [1,2], [3,4], [5,6], ];That would allow us to use convenience methods on the arrays:
const total = coolArray.reduce( (acc, arr) => acc + arr.reduce( (acc, number) => acc + number, 0 ), 0 );5. (OPTIONAL) Above form can be enhanced again with error management:
const total = coolArray.reduce( (acc, arr) => !Array.isArray(arr) ? acc : acc + arr.reduce( (acc, number) => typeof number !== 'number' ? acc : acc + number, 0 ), 0 );