Grade Statistics Calculator - javascript

I'd like to get some help on my javascript code. I made a grade statistics calculator that shows results on:
Min – Max student grade
Min – Max student average
Min – Max course grade
Min – Max course average grade
You can access it live here --> http://jsbin.com/qirefe/edit?html,css,js,output and press the "Show Results" button to see my output. (You can change the names and the grades to get a different output)
My problem is that I cannot figure out why it doesn't show the correct course names on the Min - Max course grade, although it displays the grades right. Also I cannot figure out why it calculates wrongly the min and max course average grade and displays the corresponding courses name wrong..
Any help will be very appreciated :)
The .js code:
var Course0 = Array(6);
var Course1 = Array(6);
var Course2 = Array(6);
var Student = Array(6);
var CMap = [Course0, Course1, Course2];
var NMap = ["Course0", "Course1", "Course2"];
var showResults = function () {
var Rows = document.getElementsByClassName("srow");
for (var i = 1; i < Rows.length - 1; i++) {
var values = Rows[i].getElementsByTagName("input");
Student[i - 1] = values[0].value;
for (var j = 1; j < values.length; j++) {
CMap[j - 1][i - 1] = values[j].value;
}
}
var MinID = MaxID = AvgMinID = AvgMaxID = 0;
var Min = Max = AvgMin = AvgMax = undefined;
for (var i = 0; i < Student.length; i++) {
var c0 = Course0[i];
var c1 = Course1[i];
var c2 = Course2[i];
var lessonMin = Math.min(c0, c1, c2);
var lessonMax = Math.max(c0, c1, c2);
if ((lessonMin <= Min) || (typeof Min === "undefined")) {
MinID = i;
Min = lessonMin;
}
if ((lessonMax >= Max) || (typeof Max === "undefined")) {
MaxID = i;
Max = lessonMax;
}
var Avg = Math.avg(c0, c1, c2);
if ((Avg < AvgMin) || (typeof AvgMin === "undefined")) {
AvgMinID = i;
AvgMin = Avg;
}
if ((Avg > AvgMax) || (typeof AvgMax === "undefined")) {
AvgMaxID = i;
AvgMax = Avg;
}
}
var Wrapper = document.getElementById("student-results");
Wrapper.innerHTML = "";
Wrapper.innerHTML += "<span>The Student with lower grade is: " + Student[MinID] + ", Equals To " + Min + "</span>";
Wrapper.innerHTML += "<span>The Student with higher grade is: " + Student[MaxID] + ", Equals To " + Max + "</span>";
Wrapper.innerHTML += "<hr />";
Wrapper.innerHTML += "<span>The Student with lower average grade is: " + Student[AvgMinID] + ", Equals To " + AvgMin + "</span>";
Wrapper.innerHTML += "<span>The Student with higher average grade is: " + Student[AvgMaxID] + ", Equals To " + AvgMax + "</span>";
var CourseMin = CourseMinID = CourseMax = CourseMaxID = CourseAvgMin = CourseAvgMinID = CourseAvgMax = CourseAvgMaxID = 0;
CourseMin = CourseMax = CourseAvgMin = CourseAvgMax = undefined;
for (var i = 0, j = 0; i < Student.length; i++, j += .5) {
var c0 = Course0;
var c1 = Course1;
var c2 = Course2;
var CheckMin = Math.min(c0[i], c1[i], c2[i]);
if (CourseMin > CheckMin || (typeof CourseMin === "undefined")) {
CourseMin = CheckMin;
CourseMinID = i;
}
var CheckMax = Math.max(c0[i], c1[i], c2[i]);
if (CourseMax < CheckMax || (typeof CourseMax === "undefined")) {
CourseMax = CheckMax;
CourseMaxID = parseInt(j);
}
var Avg = Math.avg(c0[i], c1[i], c2[i]);
if (Avg < CourseAvgMin || (typeof CourseAvgMin === "undefined")) {
CourseAvgMin = Avg;
CourseAvgMinID = j;
}
if (Avg > CourseAvgMax || (typeof CourseAvgMax === "undefined")) {
CourseAvgMax = Avg;
CourseAvgMaxID = parseInt(j);
}
}
console.log(CourseMaxID);
Wrapper.innerHTML += "<hr />";
Wrapper.innerHTML += "<span>The Course with lower grade have: " + NMap[CourseMinID] + ", Equals To " + CourseMin + "</span>";
Wrapper.innerHTML += "<span>The Course with higher grade have: " + NMap[CourseMaxID] + ", Equals To " + CourseMax + "</span>";
Wrapper.innerHTML += "<hr />";
Wrapper.innerHTML += "<span>The Course with lower average grade have: " + NMap[CourseAvgMinID] + ", Equals To " + CourseAvgMin + "</span>";
Wrapper.innerHTML += "<span>The Course with higher average grade have: " + NMap[CourseAvgMaxID] + ", Equals To " + CourseAvgMax + "</span>";
return null;
};
Math.avg = function () {
var Avg = 0;
var table = arguments;
for (var i = 0; i < table.length; i++) {
Avg += parseFloat(table[i]);
}
return parseFloat(Avg / table.length);
};

After examining the output of CourseMaxID and CourseMinID in the console, CourseMinID has an index of 3, but NMap only has 3 values (indexed as 0, 1, 2). So I believe this is why, for example, you are seeing:
"The Course with lower grade have: " + NMap[CourseMinID] + ", Equals To " + CourseMin; is undefined -- because the index is out of bounds.
Here's a fix for your issues with CourseMinID and CourseMaxID:
Change the definition of CourseMinID to Math.floor(j)-1;
And change CourseMaxID to be equal to Math.ceil(j);
Your call to parseInt() on a float value didn't appear to be having the intended consequence.
I'm not entirely sure why you're choosing to increment j by 0.5 each time, but from observation I noticed that for CourseMax/CourseMinID, you wanted to use the computations I noted above.
Another note, for the course average values, you are in fact outputting the student's averages. So you will want to change your logic there. It looks to me like you are giving the horizontal row of grades as parameters to the average function:
var Avg = Math.avg(c0[i], c1[i], c2[i]);
That's not what you want to parse in to Avg for course average grades. I would define another Avg function (let's call it newAvg() here) that takes as input a single array (not multiple arguments), and then call Math.Min/Math.Max on newAvg(c0), newAvg(c1), newAvg(c2).
Here's an updated jsbin link with working functionality for course averages. Overview of changes: newAvg() has been defined to take in and operate on one parameter. Keep track of indices of CourseAvgMax and CourseAvgMin. Note that I've removed some of the other operations you had earlier in this jsbin link to make it easier for me to isolate what I was working on. Hope you find it useful!

Related

For loop not storing variables?

This is my code:
<html>
<head>
<title>Temperature Information</title>
</head>
<body>
<script>
//declare variables
var BR = "<br />";
var ES = " ";
var counter;
var temp = [counter];
var max = 0;
var min = 0;
var tempTot;
var tempAve;
//loop
for (counter = 1; counter <= 5; counter++) {
tempTot = tempTot + temp[counter];
temp[counter] = prompt("Enter the temperature for noon on day #" + counter,ES);
temp[counter] = parseFloat(temp[counter]);
if (temp[counter] == temp[1]){
temp[counter] = max;
temp[counter] = min;
}else if (temp[counter + 1] > temp[counter] && temp[counter] != temp[1]){
temp[counter] = max;
}else if (temp[counter + 1] < temp[counter] && temp[counter] != temp[1]){
temp[counter] = min;
}
tempTot = tempTot + temp[counter];
}
tempAve = tempTot/4;
//display info
document.write("The average temperature is: " + tempAve + BR);
document.write("The maximum temperature is: " + max + BR);
document.write("The minimum temperature is: " + min + BR);
</script>
</body>
It is supposed to take info for the temperature for 5 days, display the average, max, and min. Everything seems to run fine, but it only displays the outcomes with a null. Am I doing something wrong? I feel like I am thinking too much about this.
There are a number of minor errors in your code. Using the browser's debugger or using console.log to check the state would help you figure out what is wrong. For example, your temp array's 0 element is undefined so when you do math on it, bad things happen ;). Also, it is easier to process your array once you have all of the elements instead doing it "on the fly". And finally, always check if the javascript library can do something for you (Math.min) instead of writing it....
oh, and I also put your code into its own function. If you look at your code in the debugger, you'll see that your variables are now all nicely contained in their own scope instead of co-mingling with the global scope.
<html>
<head>
<title>Temperature Information</title>
</head>
<body>
<script>
var tempInformation = function() {
var BR = "<br />";
var ES = " ";
var temp = [];
for (var counter = 0; counter < 5; counter++) {
var input = prompt("Enter the temperature for noon on day #" + (counter + 1), ES);
temp[counter] = parseFloat(input);
}
var sum = temp.reduce((previous, current) => current += previous);
var avg = sum / temp.length;
document.write("The average temperature is: " + avg + BR);
document.write("The maximum temperature is: " + Math.max.apply(null, temp) + BR);
document.write("The minimum temperature is: " + Math.min.apply(null, temp) + BR);
}
tempInformation();
</script>
</body>

Identify the largest value from a bunch of random numbers

Fiddle: https://jsfiddle.net/zhaem/po12voLL/1/
I wrote a script that lets me specific the number of random numbers I want to display, and the max value any of those numbers can be. Like so:
var randomLimit = 100000
var numberCount = 20
var counter = 0;
document.write("<h1>" + numberCount + " random numbers. Max value of " + randomLimit + "</h1>" );
function randomNumber(limit) {
return Math.floor( Math.random() * limit ) + 1;
}
while ( counter < numberCount ) {
document.write(randomNumber(randomLimit) + "<br>");
counter++;
}
I'm trying to figure out how I can evaluate all these numbers and identify the largest one (and make that line item bold).
I tried to do it by checking if the current "randomNum" is greater than the others, but doesn't work and doesn't seem like quite the right approach anyway as it seems like it needs to wait for all the numbers to be generated before picking the biggest? Would love any ideas.
while ( counter < numberCount ) {
var randomNum = randomNumber(randomLimit)
if (this.randomNum > randomNum) {
document.write("<strong>" + randomNum + "</strong>" + " ");
} else {
document.write(randomNum + " ");
}
counter++;
}
You can have a variable that keeps track of the largest number and update it if the current number is greater than the largest number. When you're done generating all the random numbers, find that number and bold it.
var randomLimit = 100000
var numberCount = 20
var counter = 0;
var largestNumber = -1;
document.write("<h1>" + numberCount + " random numbers. Max value of " + randomLimit + "</h1>" );
function randomNumber(limit) {
return Math.floor( Math.random() * limit ) + 1;
}
while ( counter < numberCount ) {
var currNumber = randomNumber(randomLimit);
document.write("<span>" + currNumber + "</span><br>");
if (currNumber > largestNumber)
largestNumber = currNumber;
counter++;
}
var list = document.getElementsByTagName("span");
for (var i = 0; i < list.length; i++) {
if (list[i].innerHTML == largestNumber) {
list[i].innerHTML = "<strong>" + largestNumber + "</strong>";
}
}
<body>
<div id="layer1">
</div>
<script src="randomNum.js"></script>
</body>
Generate all numbers in a array, find the max, then write them all as in this code.
It is not not the best solution, because it need 3 iterations over the array (one for generate, one for find the max, and the last one print the numbers) but I think it is clear, and I always err to readability over performance.
You can not resolve this problem with less than 2 iterations, because you can never know if the next value (being random) will be larger than the previous.
var randomLimit = 100000
var numberCount = 20
var counter = 0;
document.write("<h1>" + numberCount + " random numbers. Max value of " + randomLimit + "</h1>" );
function randomNumber(limit) {
return Math.floor( Math.random() * limit ) + 1;
}
// Generate random numbers
var randomNumbers = []
for( counter = 0; counter < numberCount; counter++ )
randomNumbers.push(randomNumber(randomLimit))
// Find max value
var maxValue = Math.max.apply(this, randomNumbers)
// Write values
randomNumbers.forEach(function(value) {
str = value;
if(value == maxValue) str = "<strong>" + value + "</strong>";
document.write(str + "<br />");
})
Depending on your application, and how lazy you feel you could generate the big number from a higher set and randomly insert it. Not random.
Otherwise the Mozilla Developer Network says use Math.max.apply or the 'spread operator'. Spread operator as per example.
var randomNums = []
while ( counter < numberCount ) {
randomNums.push(randomNumber(randomLimit));
counter++;
}
var maxIs = Math.max(...randomNums), i;
for (i=0; i<numberCount; ++i) {
var num = randomNums[i];
if (num == maxIs) {
document.write('<b>' + num + '</b><br/>');
} else {
document.write(num + '<br/>')
}
}

Javascript for loop sums

I want to find the sums of a set of numbers from a for loop
I currently have
var num = "";
for(var i = 1; i < 11; i +=1){
num = num + i;
}
console.log(num)
which gives me 12345678910 in the JS console
I want to produce 1+2+3+4+5+6+7+8+9+10=SUM
I have tried adding a "+" string:
num = num + i + "+";
but it gives me 1+2+3+4+5+6+7+8+9+10+
My question is how to add the "+" and "=" into the code and get the sum.
If you want the + to display AND the actual sum, then do this
var realSum = 0;
var num = "1";
for(var i = 2; i < 11; i +=1){
realSum = realSum + i;
num = num + "+" + i;
}
num = num + "=" + realSum;
Try this : http://jsfiddle.net/kx9b7qu7/2
Using Eval
var num = [];
for(var i = 1; i < 11; i +=1){
num.push(i)
}
var equation = num.join('+');
var sum = eval(equation);
console.log('Method 1: ',equation + '=' + sum)
Without using Eval
var num = [];
var sum = 0;
for(var i = 1; i < 11; i +=1){
num.push(i)
sum += i
}
var equation = num.join('+');
console.log('Method 2: ',equation + '=' + sum)
Make an util out of it for later use ;) There are also other ways that make use of functional approach (reduce, map) and things that aren't widely supported yet (generators, array comprehensions).
Here are some example functions for consideration and tweaking:
// kind of usual
var sumRange = function (from, to, step) {
var i,
sum = from,
str = from;
for (i = from + step; i <= to; i += step) {
sum += i;
str += '+' + i;
};
str += '=' + sum;
return str;
};
// sum of elements in arithmetic progression
var sumRangeAP = function (from, to, step) {
var i,
n,
str = from;
n = ((to - from) / step) + 1;
for (i = from + step; i <= to; i += step) {
str += '+' + i;
};
str += '=' + ((from + to) / 2) * n;
return str;
};
// memory efficiency (not creating hell a lot of strings) together with some functional stuff
// on the other hand it looks like assignment operators (+, +=) win with .join in terms of speed sometimes
// in many cases, I think, you may not give a shit about whether you use this or that
var sumRangeME = function (from, to, step) {
var i,
sum = from,
str = [from];
for (i = from + step; i <= to; i += step) {
str.push(i);
};
return str.join('+') + '=' + str.reduce(function (prevVal, curVal) { return prevVal + curVal; });
};
console.log(sumRange(0,20,1));
console.log(sumRangeAP(0,20,1));
console.log(sumRangeME(0,20,1));
console.log(sumRange(1,21,1));
console.log(sumRangeAP(1,21,1));
console.log(sumRangeME(1,21,1));
console.log(sumRange(7,36,1));
console.log(sumRangeAP(7,36,1));
console.log(sumRangeME(7,36,1));
In javascript + can also concatenate a string, if that's what seems best - it thinks you are putting two strings together so it concatenates them. Make num start as 0 instead, that should fix it.
Instead of var num="" try with var num=0, because this way the operator + is used as string concatenation. num=0 will do the job.
EDIT: I thought you wanted to see the "math" equation try the following:
var numbers = 0;
for (var i = 1; i < 11; i += 1){
numbers += i;
}
console.log(numbers);
Try this:
var numbers = [];
for (var i = 1; i < 11; i += 1){
numbers.push(i);
}
var string = numbers.join("+");
string += "=" + eval(numbers.join("+"));
console.log(string);
If you're really trying to concatenate then
num = num + "+" + i;

How to determine the highest and lowest numbers from an array that generates random numbers; JavaScript

Javascript:
var arrayLength = prompt("Enter how many elements you want?");
if(isNaN(arrayLength) || arrayLength < 1){
arrayLength = 50;
}
var array = [];
var list = "<ul>";
var totalSum = 0;
var totalOddSum = 0;
var totalEvenSum = 0;
var lowestNum = 0;
var highestNum = 0;
for(i = 1; i <= arrayLength; i++){
array[i] = parseInt(Math.random() * 15);
list += "<li>" + array[i] + "</li>";
totalSum += array[i];
if(array[i] % 2 == 0){
totalEvenSum += array[i];
}
else{
totalOddSum += array[i];
}
}
list += "</ul>";
document.getElementById("div1").innerHTML += list;
document.getElementById("div2").innerHTML += "Total Sum: " + totalSum + "<br>";
document.getElementById("div2").innerHTML += "Total Even Sum: " + totalEvenSum + "<br>";
document.getElementById("div2").innerHTML += "Total Odd Sum: " + totalOddSum + "<br>";
document.getElementById("div2").innerHTML += "Lowest Number: " + lowestNum + "<br>";
document.getElementById("div2").innerHTML += "Highest Number: " + highestNum + "<br>";
HTML:
<div id="div1">
</div>
<div id="div2">
</div>
As the title says, I want to be able to able to find the lowest and highest numbers that my array generates. What do I need to implement inside my loop in order to find the highest and lowest numbers Math.random() generates?
Thanks guys.
First of all, the initial values for minimum and maximum are wrong:
var lowestNum = 0;
var highestNum = 0;
The minimum value should be initialised as +Inf and maximum value as -Inf.
var lowestNum = Infinity, highestNum = -Infinity;
Then, add a simple condition that updates the lowest and highest found so far.
if (array[i] < lowestNum) {
lowestNum = array[i];
}
if (array[i] > highestNum) {
highestNum = array[i];
}
At the end of your loop, the variables will represent the lowest and highest number in the whole array.
You can use Math.max() and Math.min() to find the highest or lowest values in an array:
var highest = Math.max.apply(Math, array);
var lowest = Math.min.apply(Math, array);
There is no need to do your own looping. This works because both Math.max() and Math.min() will take an arbitrary number of arguments and operate on all of them, so if you use .apply() to pass the array as a series of arguments, it will evaluate the entire array in one function call.

getRange : Cannot convert Nan to Class

I tried parseInt but i really don't know where is the right place to put it in the code :
Here's the code :
function projectTime(QuelProjet) {
var tabUsers = getUsersList();
var ss = SpreadsheetApp.getActive();
var ProjectSheet = ss.getSheetByName("Liste Projets");
for (i = 1; i < 13; i++) {
//Nombre de jours du mois
var date = new Date(i + "/01/" + year);
var numProjects = getProjectNumber();
var currentMonthSheet = getSheetByMonth(tabMonth[i - 1]);
for (l = 0; l < tabUsers.length; l++) {
var firstLine = 1 + (l + 1) * 10 - 10 + (l + 1) * numProjects - numProjects;
Logger.log("Fline " + l + " : " + firstLine);
var QuelPro = parseInt(QuelProjet);
Logger.log("Quelpro : " + QuelPro);
var nbDays = getNbJours(date);
var sommeproject = 0;
var som1 = new Array(1000);
for (k = 1; k < nbDays + 1; k++) {
var Row = parseInt(firstLine + QuelPro);
Logger.log("Row : " + Row + " QuelProjet : " + QuelPro);
var Column = k + 1;
Logger.log("Column : " + Column);
var range = currentMonthSheet.getRange(Row, Column);
som1[k] = range.getValues();
//sommeproject = sommeproject + currentMonthSheet.getRange(firstLine + QuelProjet, k + 1).getValues();
}
}
}
var sommeproject = 1;
sommeproject = sommeproject + som1;
return sommeproject;
}
The problem is in this line :
var range = currentMonthSheet.getRange(Row, Column);
QuelProjet is a argument that I put like an integer in the function* when i call it in the spreadsheet
Thanks for your time
If the error is that cannot convert NaN to class, it means that either variable Row or Column or both are not integers. Your issue comes from Row not being an integer.
Since I don't know what getProjectNumber(), I can't fully debug, but this methodology should let you debug.
Use: Logger.log(typeof(variable_name)) so that you can pinpoint where the issue is.
Log the types of the following variables after defining them: numProjects, firstLine, quelPro, and row.
the logger should log 'number' each time. When it doesn't you've found your error.
If all results are 'number' it's possible that your numbers are not whoel numbers since I don't know what getProjectNumber() returns, and the getRange() function needs whole numbers

Categories