Reputation: 12271
I am building a calculator that uses two sliders like this:
I have a range of CPU and RAM data that is stored in an object like this:
var CloudPlans = {
small: {
id: 'small',
from: {
cpu: 1,
ram: 1
},
to: {
cpu: 2,
ram: 2
},
price: {
linux: 3490,
windows: 4190
}
},
medium: {
id: 'medium',
from: {
cpu: 2,
ram: 2
},
to: {
cpu: 4,
ram: 4
},
price: {
linux: 5600,
windows: 6300
}
},
large: {
id: 'large',
from: {
cpu: 4,
ram: 4
},
to: {
cpu: 6,
ram: 8
},
price: {
linux: 9500,
windows: 10200
}
},
[...more configs here]
}
Now based on the position and value of the slider, I have to check which plan the user has selected and then calculate the price of the components. Here is the function that checks the price range:
checkPlaninRange: function(cpuVal, ramVal) {
if(cpuVal >= CloudPlan.small.from.cpu && cpuVal <= CloudPlan.small.to.cpu ) {
return "small";
} else if (ramVal >= CloudPlan.small.from.cpu && ramVal <= CloudPlan.small.to.cpu) {
return "small";
}
}
As you can see I will be dealing with almost an endless list of conditionals to return the selected plan. Is there any way to simplify the storage or selection of these plan configs based on code other than conditionals or case statements?
Upvotes: 0
Views: 1868
Reputation: 48761
Well, coming back to this question, I thought I'd throw in my two cents...
I would compress your data storage a bit by using an Array so there's no more need for the min
values.
var CloudPlans = [
{ id: 'small',
maxcpu: 2,
maxram: 2,
price: {
linux: 3490,
windows: 4190
}
}, {id: 'medium',
maxcpu: 4,
maxram: 4,
price: {
linux: 5600,
windows: 6300
}
}, {id: 'large',
maxcpu: 6,
maxram: 8,
price: {
linux: 9500,
windows: 10200
}
},
// etc
].reverse(); // reverse it so the highest plan is first
Notice the .reverse()
. We're going to compare from the highest down.
Then use a reduce function:
checkPlaninRange: function(cpuVal, ramVal) {
return CloudPlans.reduce(function(plan, compare) {
return cpuVal <= compare.maxcpu &&
ramVal <= compare.maxram ? compare : plan;
}).id; // remove .id to return the entire object
}
Or if you want something a little more efficient, use a for
loop in the same way:
checkPlaninRange: function(cpuVal, ramVal) {
var plan = CloudPlans[0];
for (var i = 1; i < CloudPlans.length; i++) {
if (cpuVal <= CloudPlans[i].maxcpu &&
ramVal <= CloudPlans[i].maxram ) {
plan = CloudPlans[i];
} else break;
}
return plan.id; // remove .id to return the entire object
}
Not quite as clean, but it lets you break the loop early.
These are easy to extend with additional similar comparisons.
Upvotes: 2
Reputation: 60414
One simple thing you could do is (dynamically, up front) create arrays whose values represent the respective ranges:
var cpu = ["small", "small", "medium", "medium", "medium", "large"];
var ram = ["small", "medium", "medium", "medium", "large"];
Which you'd use like this:
function checkPlaninRange(cpuVal, ramVal) {
return cpu[Math.floor(cpuVal)] || "large";
}
checkPlaninRange(4.2); // "medium"
Upvotes: -2
Reputation: 664548
You can make a more general function from this:
function check(plan, values) {
for (var prop in values)
if (plan.from[prop] <= values[prop] && plan.to[prop] >= values[prop])
return true; // if only one property is met
return false;
}
// yet I guess this is what you want:
function check(plan, values) {
for (var prop in values)
if (plan.from[prop] > values[prop] || plan.to[prop] < values[prop])
return false; // if only one property is not met
return true; // if all properties are met
}
Now your checkPlaninRange
method could look like that:
checkSmallRange: function(cpuVal, ramVal) {
if ( check(CloudPlan.small, {cpu:cpuVal, ram:ramVal}) )
return "small";
}
Of course you also can loop your cloud plans with that:
getPossiblePlans: function(cpuVal, ramVal) {
var plans = []
for (var id in CloudPlans)
if ( check(CloudPlans[id], {cpu:cpuVal, ram:ramVal}) )
plans.push(id);
return plans;
}
As @Tomasz Nurkiewicz mentioned, an array with a defined loop order would be better here. With CloudPlans
being an object, the enumeration order is undefined (implementation-dependent) so it might return any plan when their ranges are not distinct.
Upvotes: 1
Reputation: 120198
You can loop over the config with the given vals. Something like
var planFrom, planTo, cpuInRange, ramInRange;
for (var plan in CloudPlans) {
planFrom = plan.from;
planTo = plan.to;
cpuInRange = cpuVal >= planFrom.cpu && cpuVal < planTo.cpu;
ramInRange = ramVal >= plamFrom.ram...;
if (cpuInRange || ramInRange) {
return plan.id;
}
}
Upvotes: 1
Reputation: 340743
Use an array instead:
var CloudPlans = [
{
id: 'small',
from: {
cpu: 1,
ram: 1
},
to: {
cpu: 2,
ram: 2
},
price: {
linux: 3490,
windows: 4190
}
},
{
id: 'medium',
from: {
cpu: 2,
ram: 2
},
to: {
cpu: 4,
ram: 4
},
price: {
linux: 5600,
windows: 6300
}
},
{
id: 'large',
from: {
cpu: 4,
ram: 4
},
to: {
cpu: 6,
ram: 8
},
price: {
linux: 9500,
windows: 10200
}
},
//[...more configs here]
}
Now you can simply iterate over CloudPlans
:
for(int planIdx = 0; planIdx < CloudPlans.length; ++planIdx) {
var plan = CloudPlan[planIdx];
if(cpuVal >= plan.from.cpu && cpuVal <= plan.to.cpu ||
ramVal >= plan.from.ram && ramVal <= plan.to.ram) {
return plan.id;
}
}
Upvotes: 3