How can I store looped data into an array? - javascript

I want to store all the looped data into the Course_Code and Grade arrays.
Everything works except that only the last entered value is stored. What must I do to save all the data in the array?
const MIN = 999;
const MAX = 10000;
const minLet = 64;
const maxLet = 91;
const GRADE_VALUE = 'parseInt(7)%parseInt(6)%parseInt(5)%parseInt(4)%parseInt(3)%parseFloat(1.5)';
var i;
var j;
var Grade = new Array();
var Course_Code = new Array();
while (willingnes != false) {
var willingnes = confirm('Do you want to enter new Course Code? Click OK to continue or Cancel to stop?');
if (willingnes == true) {
Course_Code = prompt('Enter your Course Code', 'AAA1000');
var Digits = parseInt(Course_Code.slice(-4)); // extract the last four digits from course code
while (Course_Code.charCodeAt(0) < minLet || Course_Code.charCodeAt(0) > maxLet || Course_Code.charCodeAt(1) < minLet || Course_Code.charCodeAt(1) > maxLet || Course_Code.charCodeAt(2) < minLet || Course_Code.charCodeAt(2) > maxLet || isNaN(Digits) || Digits < MIN || Digits > MAX) {
alert('Your input was invalid');
Course_Code = prompt('Enter your Course Code', 'AAA1000');
}
Grade = prompt('Input a valid Course grade:');
while (GRADE_VALUE.indexOf(Grade) < 0) {
alert('Invalid Course value.');
Grade = prompt('Re-enter valid course grade:');
}
}
}
alert(Course_Code);
alert(Grade);

Instead of assigning your array variables, you should use the push function to add the content.
Perhaps this would give you a better understanding of arrays:
https://www.w3schools.com/js/js_arrays.asp

This is how you assign a code to an array:
First you check the value and then you add it to the array by pushing it.
What you were doing was just assigning a new value each time.
var code = prompt('Enter your Course Code', 'AAA1000');
if (code) {
Course_Code.push(code);
}
for more info see here: https://developer.mozilla.org/nl/docs/Web/JavaScript/Reference/Global_Objects/Array/push

Related

Google sheets script, Every function combined with && operator and setting range of values to check array against

Follow up to Sending duplicate data to array, then checking if said array is empty or not to decide what code to run next, if statement not working correctly.
I'm pretty much trying to copy the conditional formatting that I put to notify users of "bad" data, but with script to prevent sending bad data and giving unique error messages. With the answer from my last question, the checks and preventing sending no data or data with duplicates works, but I'm now stuck on preventing sending of data that does not match the format of a four digit number.
My conditional formatting was to set the background color to orange on anything that was not equal to or in between 1000 and 9999, but I'm having trouble getting the scripting to work--I'm trying to use negation of anything in between those two values as the "false" that will prompt an error message, and the "true" to let the rest of the script run that will send the data and notification emails out. However, this makes it say that there are bad values even if I do have the correct data in. Removing the negation lets anything go through, like it's not actually checking it. Any ideas?
The section I'm asking about is the last else if statement:
else if (!data.every(function(num) {return num >= 1000 && num <= 9999})) {
SpreadsheetApp.getUi().alert("You have incorrectly formatted tallies, tallies must be four digits.", SpreadsheetApp.getUi().ButtonSet.OK);
}
Total code is below.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssSheet = ss.getActiveSheet();
//https://techyesplease.com/code/google-apps-script-find-duplicates-sheets/
function readData() {
var dataColumn = 3;
var firstRow = 6;
var lastRow = ssSheet.getLastRow();
var numRows = lastRow - firstRow + 1;
var columnRange = ssSheet.getRange(firstRow, dataColumn, numRows);
//var rangeArray = columnRange.getValues();
// Convert to one dimensional array
//rangeArray = [].concat.apply([], rangeArray);
var rangeArray = columnRange.getValues().flat().filter(String);
return rangeArray;
}
// Sort data and find duplicates
function findDuplicates(dataAll) {
var sortedData = dataAll.slice().sort();
var duplicates = [];
for (var i = 0; i < sortedData.length - 1; i++) {
if (sortedData[i + 1] == sortedData[i]) {
duplicates.push(sortedData[i]);
}
}
return duplicates;
}
//Use the same string for this variable as the name for the requestor for his or her column of data. E.g., John Doe
//****GLOBALS****
var targetSheet = 'All Tallies'; //replace with sheet/tab name
var targetSpreadsheetID = 'id' //replace with destination ID
var targetURL = 'url'
//var dataNotificationReceivingEmailAddresses =
//Set up to be able to easily change what emails the data notification goes to?
function sendDataAndTimestamp2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssSheet = ss.getActiveSheet();
var sourceRange = ssSheet.getRange('C6:C401');
//assign the range you want to copy, could make C6:C? No, would like dynamic.
var data = sourceRange.getValues();
var nameRange = ssSheet.getRange('C4:D4');
var nameValue = nameRange.getDisplayValue();
var tallyDateRange = ssSheet.getRange('C2');
var tallyDateValue = tallyDateRange.getDisplayValue();
var tallyDateText = 'Tallies to run on '+ tallyDateValue;
var tallyAmountRange = ssSheet.getRange(8,1);
var tallyAmount = tallyAmountRange.getDisplayValue();
var tallyAmountNumberOnly = data.filter(String).length;
//Used as tallyAmount includes text, for some cases need the number only
var thisDocumentUrl = ss.getUrl();
//Variables for the sending/source spreadsheet above
//Initial confirmation alert, need checks for blank or error tallies first. First condition needs to loop through data variable and check that if any values are numbers not between 1000 and 9999, throw up Ui alert error message. Second condition goes to result variable?
//Reference the earlier functions
var dataArray = readData();
var duplicates = findDuplicates(dataArray);
//Need to check data and have error message if duplicates.length >=1, if 0 allow, refuse if data length less than 1
if (duplicates.length !== 0) {
SpreadsheetApp.getUi().alert("Your tallies include duplicates, please remove them then try again.", SpreadsheetApp.getUi().ButtonSet.OK);
Logger.log(duplicates);
}
else if (dataArray.length ===0) {
SpreadsheetApp.getUi().alert("You have not input any tallies.", SpreadsheetApp.getUi().ButtonSet.OK);
}
else if (!data.every(function(num) {return num >= 1000 && num <= 9999})) {
SpreadsheetApp.getUi().alert("You have incorrectly formatted tallies, tallies must be four digits.", SpreadsheetApp.getUi().ButtonSet.OK);
}
/*https://www.youtube.com/watch?v=gaC290XzPX4&list=PLv9Pf9aNgemvD9NFa86_udt-NWh37efmD&index=10
Every method
var arr = [1,2,3,4];
var allTalliesGood = data.every(function(num){
return num < 9
});
//Use with num >= 1000, num <=9999, and then if true continue, if false stop and give error msg
*/
/*
dataFiltered = data.filter(filterlogic);
var filterlogic = function(tally){
if (tally >= 1000 && tally <= 9999){
return true;
} else {
return false
}
}
//if use false for good tallies, and rename dataFiltered to something like "dataBad", then check if dataBad has true matches in it...
//need to check for strings? what happens if letters/symbols in tally range?
//var dataBad = data.filter(function(tally){ return tally < 1000 || tally > 9999;});
// use OR (||) for getting tallies great than or less than, what about letters/symbols? Use NOT good range?
//https://www.youtube.com/watch?v=hPCIOohF0Fg&list=PLv9Pf9aNgemvD9NFa86_udt-NWh37efmD&index=8
//sort method link above
*/
else {
// rest of code
var result = SpreadsheetApp.getUi().alert("You're about to notify scheduler of the following number of tallies: " + tallyAmountNumberOnly, SpreadsheetApp.getUi().ButtonSet.OK_CANCEL);
if(result === SpreadsheetApp.getUi().Button.OK) {
//Code to send out emails and data
As far as I can tell in the function sendDataAndTimestamp2() you need to get rid of empty values from data. It can be done with filter(String) method:
var data = sourceRange.getValues().filter(String); // <-- here
. . .
else if (!data.every(function(num) {return num >= 1000 && num <= 9999}))
. . .
Or, I don't know, perhaps you meant dataArray instead of data:
else if (!dataArray.every(function(num) {return num >= 1000 && num <= 9999}))
Btw, the line can be shortened a bit:
else if (!data.every(x => (x >= 1000) && (x <= 9999)))

How to modify data-list element or alternative

I am working on an autocomplete text input by testing for string similarity, rather than checking for perfect character matches. This way, a dropdown like a datalists would still present the user with suggestions even if they accidentally add an extra character or spell their desired input wrong.
I have a working Javascript file that can compare the string input from an HTML text input to all the strings in a JSON file that holds about 700 school names as strings. The Javascript file then formats the HTML and passes the 10 most similar strings into an unordered list(for debugging) and into a data-list (where the user will be able to pick their correct answer).
However, datalists seem to have built-in autocomplete that check for identical groups of characters and the datalists will intelligently remove suggestions if the inputted string does not exist within the suggestion.
<input
type ="text"
id="search"
list="hsDropdown"
class ="form-control form-control-lg"
placeholder="High School Name"
autocomplete="off"
autofocus = "false"
/>
<hr/>
<p id="word"></p>
<datalist id ="hsDropdown"></datalist>
<ul id ="list"></ul>
</main>
<script src="js/script.js" type ="text/javascript"></script>
<script src="js/ukkonen/index.js" type ="text/javascript"></script>
The options within the datalist in my HTML are properly populated by my script.js with the most similar strings, but I need to find a way to override the property of the datalist tag that causes results with nonperfect matches to not appear, or
I would need to find an alternative way to make a dropdown list appear from a textbox that is not limited to hard auto-correct.
You could look at the select2 jQuery plugin and the Fuzzy search issue opened there
As per requestor, he has implemented the fuzzy_match function and embedded it into the plugin as the following:
I've also a function called matcher, which looks something like:
function matcher(term, text){
if(term.term === undefined){
return {text: text, score: 1};
}
var match = fuzzy_match(term.term, text.text);
return (match[0])?{text: text, score: match[1]}:false;
}
I also have a sorter, which sorts the matched elements, (so matching elements come at top)
function sorter(data) {
return data.filter(function(item) {
return !!item;
}).sort((a, b) => b.score - a.score)
.map(item => item.text);
}
And whenever we're invoking a select2 on a element, we're passing this matcher as a matcher option, and sorter as sorter option, which looks something like:
$("#element").select2({
placeholder: 'select a name',
matcher,
sorter
})
Here is the fuzzy_match function code provided:
/**
*
* #param pattern
* #param str
* #returns {[boolean,score,formatted]}
*/
function fuzzy_match(pattern, str) {
// Score consts
var adjacency_bonus = 55; // bonus for adjacent matches
var separator_bonus = 10; // bonus if match occurs after a separator
var camel_bonus = 10; // bonus if match is uppercase and prev is lower
var leading_letter_penalty = -3; // penalty applied for every letter in str before the first match
var max_leading_letter_penalty = -9; // maximum penalty for leading letters
var unmatched_letter_penalty = -1; // penalty for every letter that doesn't matter
// Loop variables
var score = 0;
var patternIdx = 0;
var patternLength = pattern.length;
var strIdx = 0;
var strLength = str.length;
var prevMatched = false;
var prevLower = false;
var prevSeparator = true; // true so if first letter match gets separator bonus
// Use "best" matched letter if multiple string letters match the pattern
var bestLetter = null;
var bestLower = null;
var bestLetterIdx = null;
var bestLetterScore = 0;
var matchedIndices = [];
// Loop over strings
while (strIdx != strLength) {
var patternChar = patternIdx != patternLength ? pattern.charAt(patternIdx) : null;
var strChar = str.charAt(strIdx);
var patternLower = patternChar != null ? patternChar.toLowerCase() : null;
var strLower = strChar.toLowerCase();
var strUpper = strChar.toUpperCase();
var nextMatch = patternChar && patternLower == strLower;
var rematch = bestLetter && bestLower == strLower;
var advanced = nextMatch && bestLetter;
var patternRepeat = bestLetter && patternChar && bestLower == patternLower;
if (advanced || patternRepeat) {
score += bestLetterScore;
matchedIndices.push(bestLetterIdx);
bestLetter = null;
bestLower = null;
bestLetterIdx = null;
bestLetterScore = 0;
}
if (nextMatch || rematch) {
var newScore = 0;
// Apply penalty for each letter before the first pattern match
// Note: std::max because penalties are negative values. So max is smallest penalty.
if (patternIdx == 0) {
var penalty = Math.max(strIdx * leading_letter_penalty, max_leading_letter_penalty);
score += penalty;
}
// Apply bonus for consecutive bonuses
if (prevMatched)
newScore += adjacency_bonus;
// Apply bonus for matches after a separator
if (prevSeparator)
newScore += separator_bonus;
// Apply bonus across camel case boundaries. Includes "clever" isLetter check.
if (prevLower && strChar == strUpper && strLower != strUpper)
newScore += camel_bonus;
// Update patter index IFF the next pattern letter was matched
if (nextMatch)
++patternIdx;
// Update best letter in str which may be for a "next" letter or a "rematch"
if (newScore >= bestLetterScore) {
// Apply penalty for now skipped letter
if (bestLetter != null)
score += unmatched_letter_penalty;
bestLetter = strChar;
bestLower = bestLetter.toLowerCase();
bestLetterIdx = strIdx;
bestLetterScore = newScore;
}
prevMatched = true;
}
else {
// Append unmatch characters
formattedStr += strChar;
score += unmatched_letter_penalty;
prevMatched = false;
}
// Includes "clever" isLetter check.
prevLower = strChar == strLower && strLower != strUpper;
prevSeparator = strChar == '_' || strChar == ' ';
++strIdx;
}
// Apply score for last match
if (bestLetter) {
score += bestLetterScore;
matchedIndices.push(bestLetterIdx);
}
// Finish out formatted string after last pattern matched
// Build formated string based on matched letters
var formattedStr = "";
var lastIdx = 0;
for (var i = 0; i < matchedIndices.length; ++i) {
var idx = matchedIndices[i];
formattedStr += str.substr(lastIdx, idx - lastIdx) + "<b>" + str.charAt(idx) + "</b>";
lastIdx = idx + 1;
}
formattedStr += str.substr(lastIdx, str.length - lastIdx);
var matched = patternIdx == patternLength;
return [matched, score, formattedStr];
}

Shift letters from input to the next in alpabhet

I have been searching the web and I have found a few examples about my current problem, and all seems to be addressing the same topic: deciphering text. But I cannot find anything written in javascript. I gave it a shot, but I'm stuck when trying to convert the string in to an array.
Lets say that the current alphabet is
var alpabhet=[
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','å','ä','ö'
];
And I have a string ammj, that I enter in the input. Then I want to be able to shift with right and left key and view the output of that current shift. So a shift of two (2) would result in the string cool. And a shift of 5 for the string åjjg would also result in cool.
So my main concern is, how can I convert a user input to an array with javascript?
I have a input filed:<input id="text_to_be_shifted" type="text"> and then I'm trying to loop the input and arrange into a array
var values = {};
var inputs = document.getElementById('text_to_be_shifted');
for( var i = 0; i < inputs.length; i++ ) {
values[inputs[i].name] = inputs[i].value;
}
Have a look at my fiddle: http://jsfiddle.net/p8kqmdL1/
Here you have a live and working example, with a check so that shifting letter 'a' with -1 will convert it to last letter of the alphabet 'ö', -2 to 'ä' e.t.c. and shifting last letter of alphabet with 1 will set it to 'a', with 2 to 'b' e.t.c:
var alpabhet=[
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','å','ä','ö'
];
var values = {};
var inputs = document.getElementById('text_to_be_shifted');
for( var i = 0; i < inputs.length; i++ ) {
values[inputs[i].name] = inputs[i].value;
}
function outputText(number){
var newtext = [];
var inputtext = document.getElementById('text_to_be_shifted').value.split('');
inputtext.forEach(letter=> {
var ind_ofLetter = alpabhet.indexOf(letter);
ind_ofLetter = ind_ofLetter + number;
if (ind_ofLetter < 0){
ind_ofLetter = alpabhet.length + ind_ofLetter;
}else if(ind_ofLetter > alpabhet.length-1){
ind_ofLetter = ind_ofLetter - alpabhet.length;
}
newtext.push(alpabhet[ind_ofLetter]);
});
document.getElementsByClassName('output')[0].innerHTML = newtext.join('');
}
function shiftUp() {
var currentShift = document.getElementById('currentShift');
var number = currentShift.innerHTML;
number++;
currentShift.innerHTML = number;
outputText(number);
}
function shiftDown() {
var currentShift = document.getElementById('currentShift');
var number = currentShift.innerHTML;
number--;
currentShift.innerHTML = number;
outputText(number);
}
document.onkeydown = checkKey;
function checkKey(e) {
e = e || window.event;
if (e.keyCode == '37') {
console.log('left arrow')
shiftDown()
}
else if (e.keyCode == '39') {
console.log('right arrow')
shiftUp()
}
}
<b>Current shift: </b><span id="currentShift">0</span>
<br><input id="text_to_be_shifted" type="text">
<div id='output' class="output"></div>
There is only one input, so there is no point in looping over it.
To get an array, you should use something like:
document.getElementById('text_to_be_shifted').split("");
You can then use the map function to shift the elements
let arr = document.getElementById('text_to_be_shifted').split("");
let shifted = arr.map((c) => alpabhet[(alpabhet.indexOf(c) + 1) % alpabhet.length]).join("");
in your for loop you can utilize the charAt() function to get the individual character at a given index. W3 schools has a good lesson on this function if needed: https://www.w3schools.com/jsref/jsref_charat.asp
var inputArray = [];
var inputs = document.getElemenById('text_to_be_shifted');
for(let i = 0; i < inputs.length; i++){
inputArray[i] = inputs.charAt(i);
}
Something like this should work to get you an array with a single letter at each index.

Javascript Averaging Calculator(Multiple Values entered by the user)

I want to be able to have a user enter multiple grades and then have the Javascript to average those grades that are entered. When the user is done entering grades, they can click cancel and close the Propmt Box, and if they don't enter any grades at all (defaults at 0), then the program displays that there were no grades entered.
I'm pretty new at this! I'm taking a javascript course at my College, and it's a bit confusing because the teacher doesn't teach! All we have to reference to is W3schools, which this stuff isn't listed at all!
Here's another explanation:
"Develop a program to allow a teacher to enter an arbitrary number of grades, perform an average calculation and then display the result in a grammatical sentence. The program must also tell the user if no grades were entered. You are required to use a loop and an “if else” statement. Be sure to declare all variables and test for the possibility of division by zero."
<script type = "text/javascript">
var gradeCounter = 0,
gradeValue = 0,
total = 0,
average, grade;
var sum = 0;
var i = 0;
while (gradeValue != -1 && gradeValue <= 100) {
//Prompt the user
grade = prompt("Enter Grades, -1 to Quit:", "0");
//Parse the prompt result to a int
sum += parseInt(grade);
i++;
if (i >= 0 && grade != null) {
document.getElementById("average").innerHTML = "The average of the grades you've entered are " + sum / i + ".";
} else {
document.getElementById("error").innerHTML = "There were no grades entered";
}
} </script>
Thanks again!
this does ok
updated
updated again
JSFIDDLE
// note: the dom must be ready before execution
var btn = document.querySelector('button'),
res = document.getElementById('average');
btn.addEventListener('click', function(e) {
var val = prompt('Enter comma delimited grades to average');
val = val.length ? val.replace(/\s/g, '').split(',') : '';
var count = val.length || 0; // no 0 division
if (!count) {
res.innerHTML = 'you must enter comma delimited numbers to average';
return;
} else {
var average = val.reduce(function(a, b) { // is a loop
return +a + +b;
});
res.innerHTML = (average /= count).toFixed(1);
}
});
html
<button id="avgBtn">Prompt</button>
<p>Average: <span id="average"></span></p>
var grades = [];
// initialize the array that will store the entries
var sum = 0;
// initialize the variable that will add the array values together
var average;
// initialize the variable that will contain the final result
var invalid = [];
// initialize the variable that will be used to make sure the user inserts something
for (i = 0; i < 5; i++) {
// repeat the following code 5 times
grades[i] = prompt("Please enter a grade. (You will be asked for 5 grades)", "");
// ask the user for a grade and store it to the array
}
for (i = 0; i < grades.length; i++) {
if (grades[i] === "" || grades[i] === null) {
invalid[invalid.length] = grades[i];
}
}
if (invalid.length !== 5) {
for (i = 0; i < grades.length; i++) {
// repeat this code the same amount of times as there are entries in the array (5)
sum += Number(grades[i]);
// add the entries together. make sure they are numbers using the Number() function
}
var average = sum / grades.length;
// divide the added entries by the number of entries (again, 5)
alert("The average of all of your numbers is: " + average);
// alert the user of the completed average
} else {
alert('You need to enter grades for this to work! Please reload the page to try again.');
}

How to display the contents of an array after comma splitting it in Java Script

I am fairly new to Javascript and have been picking it up pretty quickly in the past few days, after staring at my code for hours and trying to figure out why it wasn't working the way I intended i figured i would post it here.
Anyways, so my question is how do I display the WHOLE content of an array after comma splitting it. My code is below. My code is only printing out the last number set that I input at the prompt.
Help would be highly appreciated.
var gradeinfo = new Object(); {
coursecode = new Array;
grade = new Array;
};
var changer = function (y) {
finalgradeinfo = new Array;
finalgradeinfo = y;
function newresults() {
var i = 0;
finalgradeinfo[i] = y;
i + 1;
}
return finalgradeinfo;
}
do {
var entry = prompt("Enter a course code and grade seperated by a comma");
if (entry != null && entry != "") {
var counter;
var entryvalid = new Array;
entryvalid = entry.split(",");
changer(entryvalid);
x = true;
} else {
x = false;
}
} while (x != false);
console.log(finalgradeinfo);
My function needs to include closure so if it looks entirely wrong i apologize in advance.
Help from this post
Split creates an array already. So, if you enter 1,2,3, you get an array like this when you split it: ["1", "2", "3"]. In your for loop, you are getting the characters from the original input, not your array. In order to add them, you need to change the input to numbers since they are considered strings. So your for loop should look like this:
for (i=0; i<3; i++)
{
entryArray[i] = parseFloat(entryArray[i]);
}
overwriting the strings with the digits.
In changer() you're destroying and recreating the array after each input. I suggest moving the array declaration into the global scope so that you can just push elements to it in the changer() function:
Fiddle
var finalgradeinfo = [];
var changer = function (y) {
finalgradeinfo.push(y);
}
do {
var entry = prompt("Enter a course code and grade seperated by a comma");
if (entry != null && entry != "") {
var counter;
var entryvalid = entry.split(",");
changer(entryvalid);
x = true;
} else {
x = false;
}
} while (x != false);
console.log(finalgradeinfo);
Notes:
Declaring arrays as [] is preferred to new Array
Not sure if you're aware but the newresults() function and gradeinfo object aren't doing anything
Also, the counter doesn't do anything, and the x boolean is unnecessary because it's basically just checking for prompt input. Here is my approach and fiddle.
var finalgradeinfo = { // declare finalgradeinfo in the global scope
coursecode: [],
grade: [] }
, entry = '';
do {
entry = prompt('Enter a course code and grade seperated by a comma') || ''; // will set entry to '' if user hits cancel
if (entry == '') continue; // break out of iteration if string is empty
var entryvalid = entry.split(",");
finalgradeinfo.coursecode.push(entryvalid[0]);
finalgradeinfo.grade.push(entryvalid[1]);
} while(entry !== '');
console.log(finalgradeinfo);

Categories