Consider the following Objects:
// Example 1
{
gradeA: 100,
gradeB: 'No-Data',
gradeC: 'No-Data'
}
// Example 2
{
gradeA: 50,
gradeB: 40,
gradeC: 'No-Data'
}
// Example 3
{
gradeA: 75,
gradeB: 'No-Data',
gradeC: 'No-Data'
}
They represent a percentage, i.e. the sum of all three grades will be exactly 100. How can we interpolate the keys with 'No-Data'
whenever their values can be calculated?
Expected Results:
// Example 1
{
gradeA: 100,
gradeB: 0,
gradeC: 0
}
// Example 2
{
gradeA: 50,
gradeB: 40,
gradeC: 10
}
// Example 3
{
gradeA: 75,
gradeB: 'No-Data',
gradeC: 'No-Data'
}
// Note: This one can't be figured out so we leave it as is.
My solution in pseudo-code:
function interpolate(obj) {
// If only one key is a number:
// The value is 100:
// Set the other two keys to 0 and return the obj.
// The value is less than 100:
// return obj unchanged.
// If only one key is not a number:
// set that key to the sum of the two numbers minus 100 and return the obj.
}
There are two main questions here:
- How do I find out how many and which keys are
'No-Data'.
- Can I rearrange the control flow to be more efficient?
In reality, these Objects are inside an Array, but I'm sure I can figure that stuff out myself.
CodePudding user response:
Using the same logic you've described:
function interpolate(obj) {
var noData = 0;
Object.keys(obj).forEach(key => {
if (isNaN(obj[key])) {
noData ;
}
});
var sum = 0;
var missingKey;
if (noData == 1) {
Object.keys(obj).forEach(key => {
if (!isNaN(obj[key])) {
sum = obj[key];
} else {
missingKey = key;
}
});
obj[missingKey] = 100 - sum;
return obj
}
return obj;
}
var objects = [{
gradeA: 100,
gradeB: 'No-Data',
gradeC: 'No-Data'
}, {
gradeA: 50,
gradeB: 40,
gradeC: 'No-Data'
}, {
gradeA: 75,
gradeB: 'No-Data',
gradeC: 'No-Data'
}]
objects.forEach(o => console.log(interpolate(o)));
CodePudding user response:
- You can use something like this to filter for a key given a value (in your case
No-Data
).
let keys = Object.keys(obj).filter(k=>obj[k]===value);
Just count the number of items in the array to see how many you have.
- Your control flow is fine, it will be readable and its efficiency depends on how efficient you are at counting the number of occurances of
No-Data
. Tip: If you are trying to be as efficient as possible, you don't need to keep finding occurrences ofNo-Data
after you find 2 :)
Ps. There are a few issues with the other code that was posted that will probably stop you from getting full points if you turn it in :)
CodePudding user response:
In my solution I analyze each object for the combined sum of the grades and the number of No-Data values. Then I proceed to replace the No-Data values in each property of each object if conditions match. Works with any number of grades.
const objects = [{
gradeA: 100,
gradeB: 'No-Data',
gradeC: 'No-Data'
}, {
gradeA: 50,
gradeB: 40,
gradeC: 'No-Data'
}, {
gradeA: 75,
gradeB: 'No-Data',
gradeC: 'No-Data'
}];
const analysis = objects
.map( o => Object.values(o)
.reduce( ([o, sum, nodatacount], v) =>
v==='No-Data'
? [o, sum, nodatacount 1]
: [o, sum v, nodatacount],
[o, 0, 0] ) );
for(const [o, sum, nodatacount] of analysis) {
if(sum === 100 || nodatacount === 1) {
for(const [key, _] of Object.entries(o)
.filter(([_, value]) => value==='No-Data')
) {
o[key] = 100-sum;
}
}
}
console.log( objects );
.as-console-wrapper {top:0; max-height: 100% !important}
CodePudding user response:
You could first find numbers with filter
and subtract that from the length to get a length of not numbers. Then if that length is larger than 1 and there is no max value you return same object. Otherwise you find total and create return new object with correct values.
function interpolate(obj, max = 100) {
const numbers = Object.values(obj).filter(Number)
const notNumbers = Object.keys(obj).length - numbers.length
const isMax = numbers.includes(max)
if (notNumbers > 1 && !isMax) {
return obj
}
const output = {}
const total = numbers.reduce((r, e) => r e, 0);
for (const [k, v] of Object.entries(obj)) {
output[k] = typeof v !== 'number' ? isMax ? 0 : max - total : v
}
return output
}
const a = {
gradeA: 100,
gradeB: 'No-Data',
gradeC: 'No-Data'
}
const b = {
gradeA: 50,
gradeB: 40,
gradeC: 'No-Data'
}
const c = {
gradeA: 75,
gradeB: 'No-Data',
gradeC: 'No-Data'
}
console.log(interpolate(a))
console.log(interpolate(b))
console.log(interpolate(c))