Why I can't loop this function? - javascript

My teacher gave us a lesson where we had to find out how many times a x number was drawn in the lottery. He gave us a .txt document containing all datas from the previous years. He told us to build a function to discover these values. I ended up with this:
//Transfer the txt logs to variable 'conteudo'
try {
conteudo = fs.readFileSync("dados.txt", "utf8");
conteudo = conteudo.split("\r\n");
vezessort = 0;
} catch(erro) {
console.error(erro.message);
}
//Function created to review all the lines in the txt file
//First for loop is to split each line, making them an array
//Second loop is to compare the values 2 to 7 on each line, where contains the numbers drawn in the lottery
function vezSort(a){
for (i = 1; i < conteudo.length; i++){
conteudo[i] = conteudo[i].split(";");
for(j = 2; j < 8; j++){
if(conteudo[i][j] == a){
vezessort += 1;
}
}
}
}
//In this exercise we need to capture the input from user, and use it as a parameter on the function
a = parseInt(prompt('Digite um número: '));
r = vezSort(a);
console.log(`O número foi sorteado ${vezessort} vezes.`);
It works perfectly, the final values matches with the desired output he gave. The problem is, in the next question he tell us to loop the function for each number between 1 to 60. But every attempt I try to loop I get problems with this line: conteudo[i] = conteudo[i].split(";");. What I am doing wrong? (Btw, in this exercise the input from the user is not needed.)

The problem is that you're modifying the conteudo array when you call vezSort(). It's initially an array of strings, but you're changing it to a 2-dimensional array when you do conteudo[i] = conteudo[i].split(";");
You should either convert it to a 2-dimensional array just once, outside the vezSort() function, or use a local variable rather than modifying the original array.
Doint it once is more efficient, so that's how I show it:
try {
conteudo = fs.readFileSync("dados.txt", "utf8");
conteudo = conteudo.split("\r\n");
conteudo = conteudo.map(line => line.split(';'));
vezessort = 0;
} catch(erro) {
console.error(erro.message);
}
//Function created to review all the lines in the txt file
//First for loop is to split each line, making them an array
//Second loop is to compare the values 2 to 7 on each line, where contains the numbers drawn in the lottery
function vezSort(a){
for (i = 1; i < conteudo.length; i++){
for(j = 2; j < 8; j++){
if(conteudo[i][j] == a){
vezessort += 1;
}
}
}
}

.split() turns a string into an array of substrings, not an array into a string. For that, use .join().
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join

Related

Finding the sum of a variable amount of numbers in a given string

I am doing an exercise on JS Hero website:
Write a function add that takes a string with a summation task and returns its result as a number. A finite number of natural numbers should be added. The summation task is a string of the form '1+19+...+281'.
Example: add('7+12+100') should return 119.
The code I have written is as follows:
function add (string) {
let partsArray = string.split("+");
let added = parseInt(partsArray[0]);
for (let i=0; i<=partsArray.length; i++) {
added = added + parseInt(partsArray[i]);
}
return added;
}
It returns NaN. Any ideas how to solve this one?
You were going out of bounds on your array. Also you should just initialize the added to 0 as you start looking at the array from index 0. Note I added some console.logs to give you an idea of how you might debug something like this.
function add (string) {
let partsArray = string.split("+");
console.log("parts", partsArray);
let added = 0;
for (let i=0; i<partsArray.length; i++) {
console.log("i",parseInt(partsArray[i]));
added += parseInt(partsArray[i]);
}
return added;
}
If you add the <= back and run the code with the console.logs you will see in console the following. Note with the <= you have 4 indexes rather than the expected 3. This is because the size is 3 but the array is indexed from zero. When you use < you get the expected answer.
You could also use the reduce method:
function add(string) {
return string.split('+').reduce((accumulator, currentValue) => accumulator +
parseInt(currentValue, 10),0)
}
If you still want to start with the first index ..you can do it like below
function add (string) {
let partsArray = string.split("+");
let added = parseInt(partsArray[0]);
for (let i=1; i<partsArray.length; i++) {
added += parseInt(partsArray[i]);
}
return added;
}
function add(input) {
let myinput = input.split("+") //split your value
let sum = 0;
for (let i = 0; i < myinput.length; i++) {
sum = sum + +myinput[i]; //use + for identify the number value
}
return sum;
}
The simplest possible answer is:
function add(str){
return eval(str)
}

Where/how to set increment on loop and update array only when condition found?

I'm writing a function to iterate through folders on Google Drive and match files (Google Sheets) with a variable string (a date specified on a table cell). When a matching file is found, the containing folder name string is assigned to folderItems[0] and the file URL to folderItems[1]. Once all matching files within a folder have been found, the next folder is iterated through in the same way. These "folderItems" arrays are stored in a parent array "folderItemsContainer" to create a 2 dimensional array which can then be output to a spreadsheet using .setValues().
I'm having trouble figuring out how or where to put the increment variable so that it will increment only when a filename match is made but not stop a loop when a match isn't found.
I've tried various structures including interchanging for and while loops and inserting if statements where seemingly useful. I've looked at a few different answers on Stackoverflow that come close to making sense but none seem to be applicable here. I'm fairly new to programming. I've got different variations of code I've tried, but this is where I'm up to so far:
function GetFolderData() {
var currentSheet = SpreadsheetApp.getActiveSpreadsheet();
var currentYearPeriod = currentSheet.getRange("C1!A4").getValue();
// Logger.log(currentYearPeriod);
//Get folder objects from parent folder
var parentFolderId = "17F0fcBH0jmxsk2sUq723AuIY0E2G_u0m";
var parentFolder = DriveApp.getFolderById(parentFolderId);
//Get folders from specified parent folder
var StaffFolders = parentFolder.getFolders();
//Create container array
var folderItemsContainer = [];
//Create Item Array
var folderItems = [];
var i = 0;
//For every staff folder, regardless of content, do:
while (StaffFolders.hasNext()) {
//Get current folder object
currentFolder = StaffFolders.next();
//Get files in current folder object as FileIterator
FolderFiles = currentFolder.getFiles();
//If folder empty, outer while loop will iterate
if (FolderFiles !== null) {
//Iterate through existing files
while (FolderFiles.hasNext()) {
//Get file object sequentially
file = FolderFiles.next();
//When filename matches currentYearPeriod, store URL next to name in folderItems
for (i = 0; file.getName().indexOf(currentYearPeriod) !== -1; i++) {
folderItems[i] = [];
folderItems[i][0] = currentFolder.getName();
// Logger.log(currentFolder.getName());
folderItems[i][1] = file.getUrl();
folderItemsContainer[i] = folderItems[i];
}
}
}
}
return folderItemsContainer;
}
function InsertFolderData() {
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange("B4:Z1000").clearContent();
FolderData = GetFolderData();
Logger.log(FolderData);
sheet
.getRange(4, 2, FolderData.length, FolderData[0].length)
.setValues(FolderData);
Logger.log(FolderData);
/* var str = "";
for (var i = 0; i < FolderData.length; i++) {
str += FolderData[i] + "\r\n";
}
str = str.substr(0);
var ui = SpreadsheetApp.getUi();
ui.alert("DATA IMPORTED: " + "\r\n" + str);
*/
}
With the above code, I'm not entirely sure why but I seem to be getting stuck in an endless loop and the script doesn't finish. What I'm hoping to achieve is the folderItemsContainer array being populated with arrays containing file information (parent folder name[0] and file URL[1]) for files that match the currentYearPeriod variable. I've been refactoring the code and I've learned a lot but unfortunately not how to solve the problem.
You should check what's the deference between each loop, you are not fully undestending them. If you want to execute the instructions inside the for loop until a certain condition is met, in this case file.getName().indexOf(currentYearPeriod) !== -1, you should use a while loop. The bug is that the previous condition is never met because file never change while running the for loop. Thats why you are having an infinite loop. My solution:
// new variable
var cnt = 0;
while (StaffFolders.hasNext()) {
currentFolder = StaffFolders.next();
FolderFiles = currentFolder.getFiles();
if (FolderFiles !== null) {
while (FolderFiles.hasNext()) {
file = FolderFiles.next();
// You for loop started here
folderItems[cnt] = [];
folderItems[cnt][0] = currentFolder.getName();
folderItems[cnt][1] = file.getUrl();
folderItemsContainer[cnt] = folderItems[cnt];
// each time you read a new file you increment by 1
cnt++;
}
}
// this reset the counter for each new folder
cnt = 0;
}
Deferences between loops:
for loops
They are used when you know how many iteration will be needed. For example, if you want to print all the character of a string in the console:
const str = "hello";
for(let i = 0; i < str.length; i++) {
console.log(str.charAt(i));
}
let i = 0 is the starting point
i < str.length is when you want to stop. If you have to use a simbol which is not one of the follow <, <=, >, >=, you shouldn't be using a for loop.
i++ how you want to reach the stop property.
while loops
If you dont know when your loop is going to end, if it's going to have, 5 iteration, 100 iteration or 0 iteration. You should use while loops.
function getFirstL(str)
let i = 0;
while(i < str.length && str.charAt(i) !== "l"){
i++;
}
}
Your for loop. Here is syntax of for loop.
for (statement 1; statement 2; statement 3) {
// code block to be executed
}
Statement 1 is executed (one time) before the execution of the code block.
Statement 2 defines the condition for executing the code block.
Statement 3 is executed (every time) after the code block has been executed.
Your for loop doesn't define a condition for it to exit. A minimum or maximum value. something like
i<file.getName().indexOf(currentYearPeriod);
So it will check from 0-to that value.

Best way to create string filter comparation?

My goal's create a filter search function, in particular actually I'm using .indexOf method that allow me to check if two string are equal. The problem's that if I've the compare string with space break like this: Hair Cut.
Example:
String to search: Hair
String contained in the object: Hair Cut
var cerca = $('#filter_service').val();
for(var i = 0; i < GlobalVariables.availableServices.length; i++) {
if (cerca.toLowerCase().contains(GlobalVariables.availableServices[i].name.toLowerCase()) != -1) {
console.log(GlobalVariables.availableServices[i].name)
}
}
How you can see I valorize the variable cerca that contains the string Hair in the example. I compare this with an object variable, how I said, the problem is if I insert the string Hair I get no response in console, also if I insert the string with break space like the compare string Hair Cut I get the console response.
How I can print a result also when the variable cerca is equal to the first character of the compair string? In particular Hai?
I don't know if I was clear, hope yes.
.contains() is for checking DOM element children. You said above that you are using .indexOf to check, but it doesn't look like you use it in your code?
var cerca = $('#filter_service').val();
var searchIn;
for(var i = 0; i < GlobalVariables.availableServices.length; i++) {
searchIn = GlobalVariables.availableServices[i].name.toLowerCase().split(' ');
for (j = 0; j < searchIn.length; j++) {
if (cerca.toLowerCase().split(' ').indexOf(searchIn[j].toLowerCase()) >= 0) {
console.log(GlobalVariables.availableServices[i].name);
}
}
}
$('#filter_service').on('input', function() {
var inputStr = $('#filter_service').val();
var similar = [];
for (i = 0; i < GlobalVariables.availableServices.length; i++) {
if (GlobalVariables.availableServices[i].name.toLowerCase().indexOf(inputStr.toLowerCase) >= 0) {
similar[similar.length] = GlobalVariables.availableServices[i].name;
}
}
// At this point, you can do whatever you want with the similar service
// names (all of the possible result names are included in the array, similar[].)
});
I can't test that code right now, but in theory, it should work.
Here is a JSFiddle demo:
http://jsfiddle.net/MrGarretto/vrp5pghr/
EDIT: Updated and fixed my errors
EDIT 2: Added the 'possible results' solution
EDIT 3: Added a JSFiddle

How do I correctly split an array of strings of is it another issue?

I am trying to access a random element from an array of strings as per other examples here on SO. I am using Raphael.js and regions[j] below returns an array of Raphael objects - hence the .data(id). This seems to be ok, but theCountyNames, as outlined in the comment below returns all of the strings as one long string. I am guessing that this is why randCounty returns a single random letter, but when I try appending a comma in the loop (+",") and using split as per this question, I still get one random single letter. Perhaps I am implementing this incorrectly or maybe it is another issue? Thanks.
function pickRandCounty(){
var theCountyNames = new Array();
for (var j = 0; j < regions.length; j++) {
theCountyNames = regions[j].data('id');
document.write(theCountyNames);//THIS GIVES ME THE COMPLETE LIST OF ITEMS IN THE ARRAY BUT ALL AS ONE STRING
//document.write("<hr>");
}
//var randCounty = theCountyNames[Math.floor(Math.random() * theCountyNames.length)];
//document.write(randCounty);//THIS JUST RETURNS ONE RANDOM LETTER??
}
Using Array.prototype.push to append a new item to an Array.
function pickRandCounty(){
var theCountyNames = [],
j;
for (j = 0; j < regions.length; ++j) {
theCountyNames.push(regions[j].data('id'));
}
j = Math.floor(Math.random() * regions.length);
return theCountyNames[j];
}
However, this is not optimised as you can set the length of the Array in advance and you can even completely skip the loop,
function pickRandCounty(){
var j = Math.floor(Math.random() * regions.length);
return regions[j].data('id');
}
The error seems to be in this part of line.
theCountyNames = regions[j].data('id'); //wrong
theCountyNames.push(regions[j].data('id')); //right
Second mistake
document.write(theCountyNames); //it will keep on appending the string in the DOM
document.write("<br>" + theCountyNames);//right

recursive function with an array as input

I am trying to create a function that gets chest exercises from an array called chest.
This function needs to be able to pick several exercises at random, which I have done using a random pointer. To stop duplicate exercises I compare the chest exercise picked (i.e chest[pointer]) and compare it against all the values in the final array.
If the new exercise is not already in the final array, the newly picked exercise is returned and then pushed onto the final array. If it is already in the final array, the function is called recursively. The idea being that the function will run recursively until it finds a new exercise which has not already been chosen:
Get Chest:
function getChest(arr){
var pointer = 0;
//random array pointer
pointer = Math.round(Math.random() * (chest.length - 1));
//check for duplicate
for(var i = 0; i < arr.length - 1; i++){
if(arr[i].name === chest[pointer].name){
return getChest(arr);
} else {
return chest[pointer];
}
}
};
The main function uses this method to select exerises randomly. The final array is called 'day'.:
function chooseExercises(){
for(i = 0; i <= 5; i++){
ex = getChest(day);
day.push(ex);
}
}
The problem I am having is that there are still duplicates when I run it. Any idea as to what is going wrong? (I am using angularJS)
Modify your function to this,
function getChest(arr){
var pointer = 0;
//random array pointer
pointer = Math.round(Math.random() * (chest.length - 1));
//check for duplicate
for(var i = 0; i < arr.length; i++){
if(arr[i].name === chest[pointer].name){
return getChest(arr);
}
}
return chest[pointer];
};
Basically, the loop is breaking before the value is checked with its full length.
EDIT: also your loop is running over arr.length-1 times, which actually should be just arr.length.

Categories

Resources