jsFiddle --> http://jsfiddle.net/rVLN2/1/
I'm a noob - I know my script is inefficient but I'm working on it. I have an object array setup like:
var SatWaterMetric = [
{"T":0,"Psat":0.6117,"vf":0.001,"vg":206,"hf":0.001,"hfg":2500.9,"hg":2500.9},
{"T":5,"Psat":0.8725,"vf":0.001,"vg":147.03,"hf":21.02,"hfg":2489.1,"hg":2510.1},
{"T":10,"Psat":1.2281,"vf":0.001,"vg":106.32,"hf":42.022,"hfg":2477.2,"hg":2519.2},
...................................];
Then I have a function that pulls a value from the html and will interpolate the number value according to the tables.
function interpolate(myval, unit) {
if (unit == "T") {
for (var i=0;i<SatWaterMetric.length;i++) {
if (myval < SatWaterMetric[i].T) {
T_low = SatWaterMetric[i-2].T;
T_high = SatWaterMetric[i-1].T;
Psat_low = SatWaterMetric[i-2].Psat;
Psat_high = SatWaterMetric[i-1].Psat;
vf_low = SatWaterMetric[i-2].vf;
vf_high = SatWaterMetric[i-1].vf;
vg_low = SatWaterMetric[i-2].vg;
vg_high = SatWaterMetric[i-1].vg;
hf_low = SatWaterMetric[i-2].hf;
hf_high = SatWaterMetric[i-1].hf;
hfg_low = SatWaterMetric[i-2].hfg;
hfg_high = SatWaterMetric[i-1].hfg;
hg_low = SatWaterMetric[i-2].hg;
hg_high = SatWaterMetric[i-1].hg;
var factor = (myval - T_low) / (T_high - T_low);
Psatx = (1 * Psat_low) + ( 1 * factor * (Psat_high - Psat_low));
vfx = (1 * vf_low) + ( 1 * factor * (vf_high - vf_low));
vgx = (1 * vg_low) + ( 1 * factor * (vg_high - vg_low));
hfx = (1 * hf_low) + ( 1 * factor * (hf_high - hf_low));
hfgx = (1 * hfg_low) + ( 1 * factor * (hfg_high - hfg_low));
hgx = (1 * hg_low) + ( 1 * factor * (hg_high - hg_low));
Tx = myval;
break;
}
}
$('#txtpsat').val(Math.round(Psatx*100000)/100000);
$('#txtvf').val(Math.round(vfx*10000000)/10000000);
$('#txtvg').val(Math.round(vgx*100000)/100000);
$('#txthf').val(Math.round(hfx*10000)/10000);
$('#txthg').val(Math.round(hgx*100)/100);
$('#txthfg').val(Math.round(hfgx*100)/100);
} else if (unit == "Psat") {
//Repeat everything but for Psat
} else if (unit == "vf") {
//Repeat everything but for vf
} else {}
}
});
Now this is only to solve the values if "T" is known. I am trying to make a program that will determine which value was typed into ("Psat", "vg", "vf", etc...) and then evaluate all of the other numbers based on that value. The way I have this setup right now, I would essentially have to repeat all of that code for Psat, vg, vf, hg, hf, and hfg. It seems very inefficient. Is there a way to trim this down to one smooth function? .
. jsFiddle --> http://jsfiddle.net/rVLN2/1/
.
3 Answers 3
You're missing a very cool feature of javascript.
obj.Prop
is the same as
obj['Prop']
So, what you have to do is just use unit as key for the values.
2 Comments
var type = 'T'; switch (obj[type]) { // stuff }As has been mentioned, you can take advantage of the fact that referencing a property of an object can be done using both dot and array notation.
Taking this a bit further, not only can you simplify access to the incoming unit, you can also reduce the rest of your code quite a bit further.
First, by changing your markup slightly, all of the entry fields ID's will have the same pattern "txt" + key.toLowerCase():
<input type='text' size='8' id='txtt'/>
Initialize an object of highLow values with a predefined magnitude (T doesn't have one):
var highLow = {
T: {},
Psat: {magnitude: 100000},
vf: {magnitude: 10000000},
vg: {magnitude: 100000},
hf: {magnitude: 10000},
hg: {magnitude: 100},
hfg: {magnitude: 100}
};
Then the rest of your interpolate function can be modified to look something like this:
// Note 1: Started loop at 2 to avoid undefined array values
// Note 2: the redundant loops could be reduced by calculating T first
function interpolate(myval, unit) {
var key, cur, factor;
var highLow = {/*see above*/};
for (var i = 2; i < SatWaterMetric.length; i++) {
if (myval < SatWaterMetric[i][unit]) {
for (key in highLow) {
highLow[key].low = SatWaterMetric[i - 2][key];
highLow[key].high = SatWaterMetric[i - 1][key];
}
factor = (myval - highLow.T.low) / (highLow.T.high - highLow.T.low);
for (key in highLow) {
cur = highLow[key];
// This is T
if (!cur.magnitude) {
cur.result = myval;
} else {
cur.result = (1 * cur.low) + (1 * factor * (cur.high - cur.low));
}
}
break;
}
}
for (key in highLow) {
cur = highLow[key];
$('#txt' + key.toLowerCase()).val(Math.round(cur.result * (cur.magnitude || 1)) / (cur.magnitude || 1));
}
}
Version 2: This version removes the redundant looping from the previous example by refactoring the display calculation and assigning it directly to the associated highLow key and calculating the final display value inline.
Code:
// Generates a result for display using the provided magnitude to
// format the calculated value.
function calcFn(T, factor, low, high, magnitude) {
var retVal = (1 * low) + (1 * factor * (high - low));
return Math.round(retVal * (magnitude || 1)) / (magnitude || 1);
}
var highLow = {
// Initializing T with a calc function that just returns the passed in value
// This makes the calc/display loop much simpler
T: { calc: function(T) { return T; },
factor: function(T, low, high) { return (T - low) / (high - low); } },
// All other metrics will use calcFn
Psat: { magnitude: 100000, calc: calcFn },
vf: { magnitude: 10000000, calc: calcFn },
vg: { magnitude: 100000, calc: calcFn },
hf: { magnitude: 10000, calc: calcFn },
hg: { magnitude: 100, calc: calcFn },
hfg: { magnitude: 100, calc: calcFn }
};
// Note: Started loop at 2 to avoid undefined array values
function interpolate(myval, unit) {
var key, cur, factor, result, high, low;
for (var i = 2; i < SatWaterMetric.length; i++) {
if (myval < SatWaterMetric[i][unit]) {
// T is in slot 0
factor = highLow.T.factor(myval, SatWaterMetric[i - 2].T, SatWaterMetric[i - 1].T);
// Now we can simply loop through all metrics using the assigned calc function to
// generate a result for display.
for(key in highLow) {
cur = highLow[key];
low = SatWaterMetric[i - 2][key];
high = SatWaterMetric[i - 1][key];
result = cur.calc(myval, factor, low, high, cur.magnitude);
$('#txt' + key.toLowerCase()).val(result);
}
break;
}
}
}
Comments
I was beaten to it! Well, here's the implementation anyway...
Change SatWaterMetric[i].T to SatWaterMetric[unit]:
The jsFiddle.
function interpolate(myval, unit) {
for (var i=0;i<SatWaterMetric.length;i++) {
if (myval < SatWaterMetric[i][unit]) {
T_low = SatWaterMetric[i-2].T;
T_high = SatWaterMetric[i-1].T;
Psat_low = SatWaterMetric[i-2].Psat;
Psat_high = SatWaterMetric[i-1].Psat;
vf_low = SatWaterMetric[i-2].vf;
vf_high = SatWaterMetric[i-1].vf;
vg_low = SatWaterMetric[i-2].vg;
vg_high = SatWaterMetric[i-1].vg;
hf_low = SatWaterMetric[i-2].hf;
hf_high = SatWaterMetric[i-1].hf;
hfg_low = SatWaterMetric[i-2].hfg;
hfg_high = SatWaterMetric[i-1].hfg;
hg_low = SatWaterMetric[i-2].hg;
hg_high = SatWaterMetric[i-1].hg;
var factor = (myval - T_low) / (T_high - T_low);
Psatx = (1 * Psat_low) + ( 1 * factor * (Psat_high - Psat_low));
vfx = (1 * vf_low) + ( 1 * factor * (vf_high - vf_low));
vgx = (1 * vg_low) + ( 1 * factor * (vg_high - vg_low));
hfx = (1 * hf_low) + ( 1 * factor * (hf_high - hf_low));
hfgx = (1 * hfg_low) + ( 1 * factor * (hfg_high - hfg_low));
hgx = (1 * hg_low) + ( 1 * factor * (hg_high - hg_low));
Tx = myval;
break;
}
}
$('#txtpsat').val(Math.round(Psatx*100000)/100000);
$('#txtvf').val(Math.round(vfx*10000000)/10000000);
$('#txtvg').val(Math.round(vgx*100000)/100000);
$('#txthf').val(Math.round(hfx*10000)/10000);
$('#txthg').val(Math.round(hgx*100)/100);
$('#txthfg').val(Math.round(hfgx*100)/100);
}
SatWaterMetric[i-2]will beundefinedandSatWaterMetric[i-2].Twill be in a hell. It is not a thingTis not known, your code just doesn't work.myval < SatWaterMetric[i].Twhereiis less than 2.