Improve an if statement chain - javascript

if (firstPositionCpc && (firstPosition > 0 && firstPositionCpc <= maxCPC)) {
var newCPC = firstPositionCpc;
} else if (topOfPageCpc && (topOfPageCpc > 0 && topOfPageCpc <= maxCPC)) {
var newCPC = topOfPageCpc;
} else if (firstPageCpc && (firstPageCpc > 0 && firstPageCpc <= maxCPC )) {
var newCPC = firstPageCpc;
} else {
var newCPC = minCPC;
}
Here is some wrong scenario
KeywordIdReport :197857118477
campaignName :BP 2015 QC (FR)
maxCPC : 3.00
OldCPC :0.46
firstPositionCpc : --
topOfPageCpc : 0.46
firstPageCpc : 0.05
NewCPC : --
Here NewCPC needs to be a number. Hence, firstPositionCpc, topOfPageCpc and firstPageCpc need to exist and be a number.
KeywordIdReport :97483945
campaignName :BP 2015 QC (FR)
maxCPC: 3.00
OldCPC :1.96
firstPositionCpc : 4.28
topOfPageCpc : 1.68
firstPageCpc : 0.85
NewCPC : 4.28
Here NewCPC needs to be lower or equal to maxCPC. Normally, the answer should be 1.68 instead of 4.28 for NewCPC.
How could I fix the chain of if statement so that it will fix the wrong scenarios?
UPDATE
Now after improvement, how could I say that the type of firstPositionCpc, topOfPageCpc and firstPageCpc exist and need to be a number?

Hence, firstPositionCpc, topOfPageCpc and firstPageCpc need to exist and be a number.
The above doesn't really make sense given that you have 3 comparisons, so my answer will lean on the assumption that you want firstPosition > 0.
So I need to check if a value type is number and if that number is in some bound so taking your first if statement:
if (firstPositionCpc && (firstPosition > 0 && firstPositionCpc <= maxCPC)) {
var newCPC = firstPositionCpc;
}
I would change it to the following:
if(typeof(firstPositionCpc) == 'number' && firstPositionCpc <= maxCPC && firstPosition > 0){....}
typeof() reads the type of the parameter and returns a string indicating the value.
See here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof

Related

How to code else if in short if statement? [duplicate]

This question already has answers here:
shortHand if else-if and else statement
(3 answers)
Closed 3 years ago.
For example, I have code with short if statement and how can I code else if in this code?
var age = 16;
age > 18 ? console.log("> 18") : console.log("< 18");
That would work like this code
var age = 16;
if (age > 18){
console.log("> 18");
}else if(age == 18){
console.log("= 18");
}else{
console.log("< 18");
}
A hybrid approach is recommended in this case:
var age = 16;
if (age == 18) {
console.log("= 18");
} else {
console.log(age > 18 ? "> 18" : "< 18");
}
Do it with ternary expression,
var age = 16;
console.log(age === 18 ? "=18" : age < 18 ? "< 18" : "> 18")
var age = 19;
console.log(age === 18 ? "=18" : age < 18 ? "< 18" : "> 18")
var age = 18;
console.log(age === 18 ? "=18" : age < 18 ? "< 18" : "> 18")
The if way could also be written like this:
var age = 16;
if (age > 18) {
console.log('> 18')
} else if (age == 18) {
console.log("= 18");
} else {
console.log("< 18");
}
So, you could use a nested ternary in the style of the code above:
var age = 16;
age > 18 ? console.log('> 18') : age === 18 ? console.log("18") : console.log("< 18")
Note, it would be more efficient to write the ternary inside console.log, since you are always returning similar values (in this case, strings):
var age = 16;
console.log(age > 18 ? age === 18 ? '18' : '< 18' : '< 18')

Parse course in textual way from course in degrees?

So im making a compass in node-red, it should have course in degrees (int) as input and string(course) as output:
So i need function that takes in integer and gives me heading in string. How to do it simple and reliable?
I have to convert course 0-360 degrees in string for example: NORTH, NORTH-EAST, EAST......
I tried the following:
var course = parseInt(courseFloatDegrees);
var courseTxt = "";
if (course >= 349 && course <= 11 || course <= 359 && course >= 349 || course === 0) courseTxt = "N";
else if (course >= 11 && course <= 33) courseTxt = "NNE";
else if (course >= 33 && course <= 56) courseTxt = "NE";
else if (course >= 56 && course <= 78) courseTxt = "ENE";
else if (course >= 78 && course <= 101 || course == 90) courseTxt = "E";
else if (course >= 101 && course <= 124) courseTxt = "ESE";
else if (course >= 124 && course <= 146) courseTxt = "SE";
else if (course >= 146 && course <= 168) courseTxt = "SSE";
else if (course >= 168 && course <= 191 || course == 180) courseTxt = "S";
else if (course >= 191 && course <= 214) courseTxt = "SSW";
else if (course >= 214 && course <= 236) courseTxt = "SW";
else if (course >= 236 && course <= 258) courseTxt = "WSW";
else if (course >= 258 && course <= 281 || course == 270) courseTxt = "W";
else if (course >= 281 && course <= 303) courseTxt = "WNW";
else if (course >= 303 && course <= 326) courseTxt = "NW";
else if (course >= 326 && course <= 349) courseTxt = "NNW";
else courseTxt = "INVALID"
But sometimes i get nothing(null-empty string) or "INVALID". Does anybody know fast and simple way to do this without that much else if statements?
There could be ways of doing this more 'simply' in code, but your approach should work. The reason it doesn't is because your if statements are messed up around the 'N' region.
if ((course >= 349 && course <= 11) || (course <= 359 && course >= 349) || (course === 0)) courseTxt = "N";
If you look at the very first two conditions, they are illogical. More than 349 but less than 11? That's never going to happen. If you have a course of 7 degrees, that doesn't meet any of the specified criteria currently.
So the first thing to do is resolve that problem. You need to adjust the line to use OR instead of AND
if(course < 11 || course > 349) courseTxt = "N";
Now your code will be able to handle the settings either side of 360/0 degrees.
That should be enough to get your current code to work, assuming course is always less or equal to 360.
You asked if there is a way to avoid all the if statements. There are probably hundreds of ways to do this, but the simplest, other than if or case statements would probably be to use an array to look up the heading. Here is an example of how it could be done. You could obviously hardcode the step value, but this way you could update your array with any number of more granular headings, and it will still work.e
function getCourse(course)
{
// define our values
var degs = 360;
var strs =
["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"];
// make sure course is always within the expected range in case it is incremented past 360
course = course % degs;
// get the step amount based on the number of compass headings we have
var step = degs/strs.length;
// adjust for the last few degrees on the scale which will be north
if(course > degs - (step/2)) course += step/2;
// now just divide the course by the step and read off the relevant heading
var index = Math.floor(course / step);
return strs[index];
}
Nicky,
I used an approach similar to Toby's -- calculating an index into an array of course strings:
var deg = course % 360;
var dirs = ["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW","N"];
var idx = Math.round(deg * (dirs.length-1)/360);
var dir = dirs[idx];
The trick is to repeat the "N" element at the beginning and end of the array, and use Math.round(...) to jump to the closest integer index number.

Boolean expressions - getting mixed up with AND, OR logical operators and how they work

I have to convert a number to comma format. E.g 12345 => 12,345.
I have my solution :
function convert(n) {
n = n.toString();
var result = '';
var count = 0,
var idx = n.length - 1;
while (r = n[idx]) {
count++;
result = ((count % 3 == 0 && count != n.length) ? ',' : '') + r + result;
idx--;
}
return result;
}
But someone else used :
result = ((count % 3 != 0 || count == n.length) ? '' : ',') + r + result;
They both work but now I am confused about my own solution and just lost why they both work. Ah not sure if my question is clear.
!(x AND y) is equal to !x OR !y
(and you can pull a NOT out of a boolean x by double negation, for example:
x == !!x
so
x AND !y (your original expression) is equivalent to !(!x OR y)
if you remove the negation (!) from the beginning, then you actually get the Negated form and that is why the second and third values of the ternary operator are reversed in your second example.
The two expressions are equivalent, the second one is just the negated version of yours. The opposite (more or less) of == is !=, the opposite of && is ||, and the opposite of true is false.
You are placing a comma whenever the count is divisible by 3 and you aren't at the start of the number. They are not placing a comma anytime the count is not divisible by 3 or they are at the start of the number.
Assume that, count % 3 = 0 and count > n.length
Now your logic:
((count % 3 == 0 && count != n.length) ? ',' : '')
which means True && True which results in True hence the first condition after ? which is "," is selected.
Someone else logic:
((count % 3 != 0 || count == n.length) ? '' : ',')
which means 'False || False' which results in 'False' hence second condition after ? which is "," is selected.
P.S: Both are using similar logic

Need an elegant way to change the return results of a in line if statement based on inputs

To better explain what Im trying to do Im going to preface a bit with no code and then show you the code I am working with in the pertinent pieces.
I currently and working with a function that measures the width and height of a canvas element and divides half of each size by an inputted number. I then decide if the resulting number is even by using math.ceil() and %2===0. Using this formula I will decide if the width is boolean true or false and the same for the height.
In the end I will have
var A = True (or False)
var B = True (or False)
I then have the creation of a 3 dimensional array:
var pax = [];
for (var i = 0; i < stage.height()/12; i++){
pax[i] = [];
for (var j = 0; j < stage.width()/12; j++){
pax[i][j] = [];
pax[i][j].push("if statement here");
};
}
I need an elegant way to replace "if statement here" with something like a double if statement where
if (A === B) {
(((i%2)===0)===((j%2)===0)) ? 0 : 180)
||
(((i%2)===0)!==((j%2)===0)) ? 180 : 0)
} else {
(((i%2)===0)===((j%2)===0)) ? 180 : 0)
||
(((i%2)===0)!==((j%2)===0)) ? 0 : 180)
};
Im pretty sure this monstrosity that I just typed wont work, so I need both the correct way to type the syntax and a more elegant and resource light way to do it, just due to the amount of index locations I will be pushing to in the array.
Basically what Im trying to do is say "Based on the height and width of the canvas, if i is even, return 0, and if i is odd, return 180, OR based on the height and width of the canvas, if i is even, return 180, and if i is odd, return 0.
I can attempt to explain this again if this is unclear.
You want your modulus operations to match or not match. With x % 2, there can only be one of two results, so there's no point in converting to a boolean with ===. And the parens are just excessive. All that clutter doesn't help. So here's a first pass:
if (A === B) {
(i%2===j%2 ? 0 : 180) || (i%2!==j%2 ? 180 : 0)
} else {
(i%2===j%2 ? 180 : 0) || (i%2!==j%2 ? 0 : 180)
}
Then it seems that you want the numbers flipped based on comparison to A === B. So if they are equal and even you want 0, 180 or if they are unequal and odd, you want 180, 0. So basically if the i/j comparison and the A/B comparison are the same, you have one result, otherwise, the other.
The odd thing is that when one % test succeeds but yields 0 the || operation makes it attempt the opposite % test, which of course will fail. But because the numbers are reversed for the second test, we end up with the correct value. It's just that you're going about it in a roundabout way.
Ultimately, what your code does is simply this:
(A === B) === (i%2===j%2) ? 0 : 180
Here's a demo that shows that your original and short version achieve the same result.
DEMO: http://jsfiddle.net/jDWf6/3/
(EDIT: Updated demo to show all values tested.)
The condition:
if (A === B) {
(((i%2)===0)===((j%2)===0)) ? 0 : 180)
||
(((i%2)===0)!==((j%2)===0)) ? 180 : 0)
} else {
(((i%2)===0)===((j%2)===0)) ? 180 : 0)
||
(((i%2)===0)!==((j%2)===0)) ? 0 : 180)
};
(There's no need for a semi–colon after a block statement)
is overly complex and can be reduced to (assuming it should return something):
var result;
if (A === B) {
result = i%2 == j%2? 0 : 180 || i%2 != j%2? 180 : 0;
} else {
result = i%2 == j%2? 180 : 0 || i%2 != j%2? 0 : 180;
}
In the first assignment, the two || operands return the same value for any given values of i and j, so it might as well be:
result = i%2 == j%2? 0 : 180;
since if i%2 == j%2 returns true, then:
i%2 == j%2? 0 : 180
returns 0, which converts to false, so the second expression is evaluated:
i%2 != j%2? 180 : 0
and i%2 != j%2 must return false (since the opposite was true) and again 0 is returned. The exact opposite occurs if the original expression returned false:
i%2 == j%2? 0 : 180
returns 180, which is truthy, so the otehr side of the || is not evaluated.
So now you have:
if (A === B) {
result = i%2 == j%2? 0 : 180;
} else {
result = i%2 == j%2? 180 : 0;
}
That means that the result of:
i%2 == j%2? 0 : 180
is reversed based on A === B, so:
result = A === B? (i%2 == j%2? 0 : 180) : (i%2 == j%2? 180 : 0)
Of course this could be way off if your pseudo code isn't doing what you hoped…
ok my friend based on what you asking here is the answer.
*I don't know if this will be what you will looking for because your logic is a bit complicated and not so correct....
As you can see i reduced the code and i maximized the performance. Also i make clear what "i" is and what "j". Just to be more readable...
var pax = [];
var isHeightEven, isWidthEven;
for (var height = 0; height < stage.height() / 12; height++) {
pax[height] = [];
for (var width = 0; width < stage.width() / 12; width++){
pax[height][width] = [];
isHeightEven = !(height % 2); //calculate only once
isWidthEven = !(width % 2); //calculate only once
pax[height][width].push(
(A === B) ? ((isHeightEven && isWidthEven) ? 0 : 180) : ((isHeightEven && isWidthEven) ? 180 : 0)
);
};
}

Updating the random number within a variable?

How can a variable with a random number be updated. I'm using three.js. Here is my code. It works the first time it's called generating a sprite to a random location but then it just keeps going back to the same location. I thought that by calling the variables before they were used I would be updating them but it's not working.
var locX = Math.floor((Math.random()*450)+1);
locX *= Math.floor(Math.random()*2) == 1 ? 1 : -1;
var locY = Math.floor((Math.random()*250)+1);
locY *= Math.floor(Math.random()*2) == 1 ? 1 : -1;
var locZ = Math.floor((Math.random()*350)+1);
locZ *= Math.floor(Math.random()*2) == 1 ? 1 : -1;
function spriteAI1() {
//console.log(c2Sprite.position.x);
//console.log(ranLocX);
//console.log(ranTen);
if (c2Sprite.position.x > 30 && c2Sprite.position.x <= 450) {
c2Sprite.translateX( -10 );
} else if (c2Sprite.position.x < -31 && c2Sprite.position.x >= -450) {
c2Sprite.translateX( 10 );
} else if (c2Sprite.position.z < 31 && c2Sprite.position.x < 31 && c2Sprite.position.z > -29 && c2Sprite.position.x > -29) {
locX;
locY;
locZ;
//c2Sprite.delete;
//scene.remove(c2Sprite);
//console.log("AI1");
c2Sprite.position.set( locX, locY, locZ );
//scene.add( c2Sprite );
//c2Sprite.clone;
}
}
If you want different values each call, declare the vars inside the function, not outside of it. As you currently have it, the vars are set once, and the function, however many times it's called, will reference those once-set values.

Categories

Resources