I'm writing a script for my schools web form for calculating credits and gpa values. When I run the input for letter grades I convert to uppercase and then check with if/else statements for A-F options and convert the value of the input to a number value which is then passed to another function to average the total for the column inputs which is then returned back to a letter grade. The issue i'm having is that when i use my keyup jquery function it returns a NaN value instead of a letter... HELP
function CalcGPA(a,b,c,d,e,f,g,h,i,j){
var initial=a+b+c+d+e+f+g+h+i+j;
var total=initial/10;
return total;}
function Convert(a){
var b=a.value.toUpperCase();
if(b.value="A")
{
b=4.0;
return b;
}
else if(b.value="A-")
{
b=3.67;
return b;
}
else if(b.value="B+")
{
b=3.33;
return b;
}
else if(b.value="B")
{
b=3.0;
return b;
}
else if(b.value="B-")
{
b=2.67;
return b;
}
else if(b.value="C+")
{
b=2.33;
return b;
}
else if(b.value="C"){
b=2.0;
return b;
}
else if(b.value="C-")
{
b=1.7;
return b;
}
else if(b.value="D")
{
b=1.0;
return b;
}
else {
b=0.0;}
return b;}
function toLetter(a){
if(a<=4||a>=3.68)
{
a="A";
}
else if(a<=3.67 || a>=3.34)
{
a="A-";
}
else if(a<=3.33 || a>=3.1)
{
a="B+";
}
else if(a<=3.0 || a>=2.68)
{
a="B";
}
else if(a<=2.67 || a>=2.34)
{
a="B-";
}
else if(a<=2.33 || a>=2.1)
{
a="C+";
}
else if(a<=2.0 || a>=1.8)
{
a="C";
}
else if(a<=1.7 || a>=1.4)
{
a="C-";
}
else if(a<=1.3 || a>=1.1)
{
a="D+";
}
else if (a=1.0)
{
a="D";
}
else {
a="F";}
return a;}
You should use parseInt or parseFloat in your toLetter function I suppose, and in your if statements, use two equal signs instead of one in order to compare:
function toLetter(a) {
var a = parseInt(a); //or parseFloat if you need decimals.
//rest of your code...
I strongly recommend a little refactoring here, for instance, instead of declaring and then returning, just return:
else if(b.value == "B+")
{
return 3.33;
}
Another improvement, move your statements to a switch:
switch(b.value) {
case "B+" :
return 3.33;
case "B" :
return 3.0;
}
And, one thing I would do, instead of conditions or cases, use a map:
var scoresForValues = {
"A": 4.0,
"A-": 3.67,
"B+": 3.33 //Keep filling until you get all your values.
};
And then your Convert function would be really simple and short:
function Convert(a) {
var b = a.value.toUpperCase();
return scoresForValues[b];
}
Use parseInt for integers or if you want to use decimal values, use parseFloat.
There are a couple of things here:
First, you are trying to compare using "=", and that can't work. You need to use "==". For example, else if(b.value="C+") should be else if(b.value=="C+")
Second, you've made b a string when you declared it and assigned the input to it:
var b=a.value.toUpperCase();
So, don't assign the numerical value to it and return it, just return the numerical value. Same for your a variable in toLetter. Just return the letter value and you can bail out of all your elseif lines as soon as you have a match.
So, instead of a="B-";, just return "B-"
finally, you should probably use switch case instead of your pile of if... else if. NOTE: you don't need break; after return 3 (for instance) because a return bails you out of the function. If you're using case switch for anything not causing a return, leaving out break; will cause you a lot of hurt.
function Convert(a){
var b=a.value.toUpperCase();
switch (b) {
case "A":
return 4.0;
break;
case "A-":
return 3.67;
break;
case "B+":
return 3.33;
break;
case "B":
return 3;
break;
case "B-":
return 2.67;
break;
case "C+":
return 2.33;
break;
case "C":
return 2;
break;
case "C-":
return 1.67;
break;
case "D":
return 1;
break;
default:
return 0;
}
Related
I can't implement the function tipPercentage that takes the argument rating as a string and return the values:
terrible or poor, then returns 3
good or great, then returns 10
excellent, returns 20
none of the above, returns 0
the input format for custom testing must be that the first line contains a integer, n, denoting the value of rating
HELP FOR A BEGGINNER!!!
You can use a switch statement to do this relatively easily, we check the input rating, then return the relevant tip percentage.
If we don't have a tip percentage for the rating, we'll fall back to the default condition, and return 0.
One could also use a map, though a switch statement is probably more flexible.
// Takes rating as a string and return the tip percentage as an integer.
function tipPercentage(rating) {
switch ((rating + "").toLowerCase()) {
case "terrible":
case "poor":
return 3;
case "good":
case "great":
return 10;
case "excellent":
return 20;
default:
return 0;
}
}
let ratings = ["excellent", "good", "great", "poor", "terrible", "meh", null];
for(let rating of ratings) {
console.log(`tipPercentage(${rating}):`, tipPercentage(rating))
}
function tipPercentage(rating) {
switch(rating) {
case "terrible":
case "poor":
return 3; break;
case "good":
case "great":
return 10; break;
case "excellent":
return 20; break;
default:
return 0;
}
}
Instead of a switch statement you could simply use an object:
const tipPercentage = {
'excellent': 20,
'good': 10,
'great': 10,
'terrible': 3,
'poor': 3,
}
const myRatings = [
"excellent",
"good",
"great",
"terrible",
"whatever",
undefined
];
for (let rating of myRatings) {
// Tip percentage, or 0 if it doesn't exist
console.log(rating, tipPercentage[rating] || 0)
}
I am trying to determine the largest prime factor of a number by working backwards from the largest possible factor. Once a factor is found, I test to see if it is prime by using the PrimeTest3 function within the original function.
However, it is not giving me the answer I am expecting for the number 13195. When I test the code as shown above using the 'this passed the test' statement, I can see that it is skipping from the first factor found (2639) to the last factor found (5), and strangely, when logging the the result of passing i through PrimeTest3, it shows up as false, even though it had to have been true to pass the if statement in the first place.
var largestPrimeFactor3 = function (num) {
function PrimeTest3(a){
if (a<=1 || a%1!=0)
return false;
limit = Math.ceil(Math.pow(a,.5));
if (a%2==0 || a%3==0)
return false;
if (a==2 || a==3)
return true;
for (i=6;i<limit;i+=6){
if (a%(i-1)==0)
return false;
if (a%(i+1)==0)
return false;
}
return true;
}
for(var i = Math.floor(num/2); i>0; i--){
console.log(i);
if(num % i === 0 && PrimeTest3(i)){
console.log('this passed the test:' + PrimeTest3(i));
return true;
}
}
}
console.log(largestPrimeFactor3(13195));
Would really appreciate any help or clarification. Thanks!!
The for loop inside PrimeTest3 is using the same variable i as the loop in largestPrimeFactor3. You need to declare this variable as local to the internal function, with a var declaration.
var largestPrimeFactor3 = function (num) {
function PrimeTest3(a){
if (a<=1 || a%1!=0)
return false;
limit = Math.ceil(Math.pow(a,.5));
if (a%2==0 || a%3==0)
return false;
if (a==2 || a==3)
return true;
for (var i=6;i<limit;i+=6){
if (a%(i-1)==0)
return false;
if (a%(i+1)==0)
return false;
}
return true;
}
for(var i = Math.floor(num/2); i>0; i--){
console.log(i);
if(num % i === 0 && PrimeTest3(i)){
console.log('this passed the test:' + PrimeTest3(i));
return true;
}
}
}
console.log(largestPrimeFactor3(13195));
You're having unexpected results because you're changing the value of i in PrimeTest3.
if(num % i === 0 && PrimeTest3(i)){ // i changed in PrimeTest3
// now i is not what it was when originally passed in PrimeTest3
console.log('this passed the test:' + PrimeTest3(i));
A fix would be to change:
for (i=6;i<limit;i+=6){
To:
for (var i=6;i<limit;i+=6){
This will localize the i variable to not change the other i variable outside PrimeTest3's function scope.
While you're at it, localize limit to the scope of PrimeTest3 by doing var limit = ... instead of just limit = ....
I would like to write regex for matching an application version in javascript using pattern:
(0-255).(0-255)[.(0-65535).(0-65535)]
Here is my result:
^(?:(\d+)\.){1}(?:(\d+)\.){1}(?:(\d+)\.)?(\d+)?$
But it allows strings with dot in the end (like '111.222.333.') and doesn't limit number of digits.
Any help?
Update
This pattern is better:
(0-255).(0-255)[.(0-65535)][.(0-65535)]
The result is:
^(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])[.](?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])(?:(?:[.](?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])){1})?(?:(?:[.](?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])){1})?$
I think the best solution for you would be to split by . and check each part:
function isInBounds(value, min, max) {
return !isNaN(value) && value >= min && value <= max;
}
function checkVersion(version) {
var parts = version.split(".");
switch (parts.length) {
case 4:
case 3:
for (var i = 2; i < parts.length; i++) {
if (!isInBounds(parseInt(parts[i], 10), 0, 65535)) {
return false;
}
}
// fallthrough
case 2:
for (var i = 0; i < 2; i++) {
if (!isInBounds(parseInt(parts[i], 10), 0, 255)) {
return false;
}
}
break;
default:
return false;
}
return true;
}
console.log(checkVersion("foo")); // false
console.log(checkVersion("foo.bar")); // false
console.log(checkVersion("foo.bar.foo")); // false
console.log(checkVersion("foo.bar.foo.bar")); // false
console.log(checkVersion("256")); // false
console.log(checkVersion("256.256")); // false
console.log(checkVersion("256.256.65536")); // false
console.log(checkVersion("256.256.65536.65536")); // false
console.log(checkVersion("42")); // false
console.log(checkVersion("42.42")); // true
console.log(checkVersion("42.42.42")); // true
console.log(checkVersion("42.42.42.42")); // true
See on jsFiddle
Regex is probably not the way to go, since it does not handle ranges very good. Just for the challenge, here is the one you would need (RegexForRange helped a lot ;)):
^(?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])[.](?:[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])(?:(?:[.](?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])){1,2})?$
Visualization by Debuggex
I want to write a function that checks if the given number has a certain order.
The second number has to be the square of the previous number.
The first number can only be 0 - 9.
So for example 2439 would return 'true' because 4 is the square of 2 and 9 is the square of 3.
39416 would also give 'true', and for example 1624 would return 'false'.
I don't really have an idea how to do this. It should be a recursive function but an example of how to do it without recursion would be helpfull too.
I would try something like this:
function isOrdered(input){
var position = 0;
while(position<input.length-2)
{
var currentFirstNumber = parseInt(input[position]);
if(currentFirstNumber<=2) {
if (Math.sqrt(parseInt(input[position + 1])) !== currentFirstNumber)
return false;
else
position+=2;
}
if(currentFirstNumber>=4 && currentFirstNumber<=9)
{
var squared = input.substring(position+1,position+3);
if(Math.sqrt(parseInt(squared))!==currentFirstNumber)
return false;
else
position=position+3;
}
}
return true;
}
console.log(isOrdered("2439")); // outputs true
console.log(isOrdered("39416")); // outputs true
console.log(isOrdered("1624")); // outputs false
I pass the number to the function as a string.
Take a look at this recursive function
function detectOrder(input)
{
var input = input.toString()
var first = input.substr(0,1);
var power = Math.pow(parseInt(first), 2);
var powerLength = power.toString().length;
if ( parseInt(input.substr(1, powerLength)) == power )
{
if (input.length <= 1+powerLength)
{
return true;
}
else
{
return detectOrder(input.substr(1+powerLength));
}
}
else
{
return false;
}
}
As mention in the comment section, OP said that the 'firsts' are limited to 0..9. So the easiest way to accomplish this is by going through the power function instead of the square root function.
UPDATE: Sorry, you asked for JavaScript code. Be careful with the FIRST CALL. if you manually pass to the function the last position, it will return true.
function verification(number, position){
var str = String(number); // Cast number to String
if(str.length > position){ // Verify valid position
var value = str.substr(position, 1); // take the 'first' value
var pow = Math.pow(value, 2); // Calculate the power
// Verify if the next value is equivalent to the power
if(str.indexOf(pow, position) == position + 1){
// Recursive call to verify the next position
return verification(number, position + String(pow).length + 1);
} else {
// If not equivalent, you found an inconsistency.
return false;
}
// If you ran it until you reached the last position, you're good to go.
}else if(str.length == position){
return true;
}
}
console.log(verification(39416, 0)); // True
console.log(verification(39415, 0)); // True
console.log(verification(981524, 0)); // false
console.log(verification(981525, 0)); // true
console.log(verification(98525, 0)); // false
I've tried making this calculator for some time now and to me everything looks just right but it won't work no matter how many times I've gone over the code. I'm going mad over this! How can this not work? Nothing happens when I hit Calculate! Please help me with this one!
Here's the JavaScript:
function calc() {
var num1, num2;
var sign = "+";
var result;
function getNum1() {
num1 = document.getElementById('num1').value;
return Number(num1);
}
function getNum2() {
num2 = document.getElementById('num2').value;
return Number(num2);
}
function getSign() {
sign = document.getElementById('sign').value;
return sign;
}
function setResult() {
document.getElementById('result').value = result;
}
function doCalc() {
var num1 = getNum1();
var num2 = getNum2();
if(getSign() == "*") {
result = num1 * num2;
}else if(getSign() == "/") {
result = num1 / num2;
}else if(getSign() == "-") {
result = num1 - num2;
}else{
result = num1 + num2;
}
setResult();
}
}
If you're invoking doCalc(), it's not reachable because it's scoped inside the calc() function.
If you're invoking calc(), it doesn't do anything because it never invokes doCalc().
If you add a doCalc() invocation to the end of the calc() function, and if your calc() function is reachable, it'll work.
Make sure you use .value on form fields and .innerHTML on everything else (spans, ps, etc.). .innerHTML gets or sets the inside of an element.
Also, make sure that the submit button has an event handler for onclick--the easiest method is <input onclick="doCalc();" ... />.
I would try decoupling the calc() function. Here is one way to go about it.
var Calculator = {
"eval" : function(operator, x, y) {
switch( operator ) {
case "+":
return (x + y);
case "-":
return (x - y);
}
}
}
Better yet,
var Calculator = {
"eval" : function(operator) {
var args = Array.prototype.slice.call(arguments);
args.splice(0,1); // lazy hack to remove the argument for the operator
switch( operator ) {
case "+":
return args.reduce( function(x,y){ return (x + y); } );
case "-":
return args.reduce( function(x,y){ return (x - y) } );
}
}
}
This way it's much easier to re-use and test.
var answer = Calculator.eval( '+', 20, 20, 2 ); // yay, prefix notation
The second variation uses the higher order function 'reduce' that reduces an array into a single value.
Here are the steps on how reduce works. I've pulled out the lambda function to make things a little more clear.
var arr = [20, 20, 20];
function sum(x, y){ return (x + y); }
function reduceMagic(arr){
var temp = sum(arr[0], arr[1]); // temp -> 40
temp = sum(temp, arr[2]); // temp -> 42
return temp;
}