Removing alert from code forces it to enter infinite loop - javascript

I have a piece of code that has a few window alert messages. It works fine. However, if I remove the alert statements, the program enters into an infinite loop. This is weird for me.
Can someone help me identify the problem with the code?
function countSwaps(arr) {
let notVisited = {}, swaps = 0;
for (let i = 0; i < arr.length; i++) {
notVisited[i] = true;
}
while (Object.keys(notVisited).length) {
alert("main pass");
let nextPos, currentPos = Object.keys(notVisited)[0];
while (arr[currentPos] !== parseInt(currentPos+1)) {
nextPos = arr[currentPos] - 1;
[arr[currentPos], arr[nextPos]] = [arr[nextPos], arr[currentPos]];
swaps+= 1;
alert("Swap " + arr[currentPos] + " and " + arr[nextPos] + "\n");
delete notVisited[nextPos];
}
delete notVisited[currentPos];
}
return swaps;
}
console.log(countSwaps([2,3,4,1,5]));

Well, it runs an infinite loop for me without the alerts as well.
It seems like the problem is the following expression: parseInt(currentPos+1)
The addition happens before the conversion from a string to a number, so for example:
currentPos = '4';
currentPos + 1 == '41';
parseInt(currentPos + 1) == 41
What you want is probably parseInt(currentPos) + 1. Now:
currentPos = '4';
parseInt(currentPos) + 1 == 5
With this the loop seems to quit and I get the result of 3 swaps out of it.

This is cause of infinite loop.
while (Object.keys(notVisited).length)
It should be something like
while (Object.keys(notVisited).length > 0)
That is a property, it will always return true

Related

How to make loop wait for user action and based on user input break out of loop

I want to make loop wait for user input and based on user input. I want to continue to iterate to next incremental value or break out of loop, but the loop completes a full revolution regardless of input and when input is given. It runs the internal loop twice again, whereas I want user input for each loop/revolution and based on that, I can continue or break the loop.
for (i = 0; i < 1; i++) {
console.log(i);
for (x = 0; x <= 1; x++) {
console.log("Before Event = " + x);
document.querySelector(".top-bar").addEventListener("click", function(event) {
var z = event.key; // Will be some key inalid input
var a = "A";
console.log("After Event = " + x);
if (a !== z) {
console.log("Expected A but Clicked = " + z);
}
console.log("Outside loop = " + x);
});
}
}
Console Log:
0
Before Event = 0
Before Event = 1
undefined
After Event = 2
Expected A but Clicked = undefined
Outside loop = 2
After Event = 2
Expected A but Clicked = undefined
Outside loop = 2
It was hard to tell what you were trying to accomplish, so I took a guess. First off, you can't combine a for-loop with input events. Instead you just have the event and keep track of how many times it gets used. To catch key presses use the keydown event. I used a counter called wrong and increment it in that console.log with ++wrong
let wrong = 0
document.querySelector(".top-bar").addEventListener("keydown", function(event) {
let z = event.key
if (z !== "A") {
console.log("Expected A but Clicked = " + z + ". You've gotten " + ++wrong + " wrong so far");
} else console.log("RIGHT!")
});
input a letter: <input class='top-bar' />

JavaScript - Simple If inside For

Having an issue with the following as I learn JS basics. My If was working before I stuck it inside the For, but now nothing seems to be working. Thought about doing forEach but seems like a complex solution for such a simple problem (creating another function to run forEach with). Also been running it through online code checkers and it is coming back clean.
Hoping I'm doing something ignorant like misaligned tabs..
"use strict";
function scan(inputArray) {
var count = 0,
iter = 0,
len = inputArray.length;
for (iter = 0; iter < len; iter + 1) {
console.log("inside for: " + iter); //diagnostic line, does not display
if (inputArray[iter] === "contraband") {
console.log("inside if: " + iter); //diagnostic line, does not display
count += 1;
} //end if
} //end for
return count;
} //end function -scan-
// Test Code
const numItems = scan(['contraband', 'dog', 'contraband', 'cat', 'zippers', 'contraband']);
console.log('Number of "contraband": ' + numItems); // should be 3
In a for loop you need to have 3 statements, which are:
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.
The reason why your code is not working is that you had a mistake in the 3rd statement, where you wrote iter + 1, without really changing the value of iter. What you had to do is write in the 3rd statement iter = iter + 1 OR iter += 1 OR iter++, and all of these change the value of iter to +1.
The for loop should be like this:
for(iter = 0; iter < len; iter++) {
...
}
Please try below code.
the iter variable should be less than length of the array
The iter should be incremented to make the access to elemenst of the array.
"use strict";
function scan(inputArray) {
var count = 0,
iter = 0,
len = inputArray.length;
for (iter = 0; iter < len; iter++) {
console.log("inside for: " + iter); //diagnostic line, does not display
if (inputArray[iter] === "contraband") {
console.log("inside if: " + iter); //diagnostic line, does not display
count += 1;
} //end if
} //end for
return count;
} //end function -scan-
// Test Code
const numItems = scan(['contraband', 'dog', 'contraband', 'cat', 'zippers', 'contraband']);
console.log('Number of "contraband": ' + numItems); // should be 3

Having trouble counting iterations of different outputs in my javascript code

Trying to set up code to take inputted numbers, determine whether they are negative or positive, displaying this, and then when 0 is put in the code displays the amount of positive numbers put in and the amount of negative numbers put in and then terminates. Having trouble with the counting part and I am not sure how to set this up better. I am also not sure how to set this up to terminate after 0 is put in.
function mapping() {
var num = parseInt(document.getElementById("num1").value);
var countp = 0;
var countn = 0;
if (num !== 0) {
if (num > 0) {
document.getElementById("output").innerHTML = "positive";
countp += 1;
} else {
document.getElementById("output").innerHTML = "negative";
countn += 1;
}
} else {
document.getElementById("output").innerHTML = "countp: " + countp;
document.getElementById("output").innerHTML = "countn: " + countn;
}
}
Thank you.
Two problems with the code.
1st: You need to move countp and countn outside of the function to make them global.
2nd: You are writing the positive number counts to output's html and then you are overriding it by negative count.
This should do the trick;
var countp = 0;
var countn = 0;
function mapping() {
var num = parseInt(document.getElementById("num1").value);
if (num !== 0) {
if (num > 0) {
document.getElementById("output").innerHTML = "positive";
countp += 1;
} else {
document.getElementById("output").innerHTML = "negative";
countn += 1;
}
} else {
var html = "countp: " + countp + ", countn: " + countn;
document.getElementById("output").innerHTML = html;
// this line added
countp = 0, countn = 0;
}
}
<input type="text" id="num1">
<button onclick="mapping()">Test</button>
<div id="output">
</div>
The main issue with the code is that countp and countn are local variables. Thus they are created and initialized to 0 every time the function is called. Move the two lines outside the function to fix this bug!
Another bug is the code in the last else part. There you set innerHTML twice, so the div ends up with only countn. To fix this bug, replace the last innerHTML = by innerHTML +=.
Finally, if I understand you correctly, you want that no more updates occur once 0 has been entered. To achieve this, you could add another variable like isFinal that is set to true when the user enters 0, and add a check to your function.
Some more suggestions:
Instead of if (num!==0), it is considered good practice to start with positive conditions such as if (num === 0). That way, you will also avoid some nesting in the conditions.
What happens if the user does not enter a valid number? In your code, this will be treated as negative number. Add a test for "NaN" to fix this.
You repeat the document.getElementById... many times. Use a temporary variable to fix this.
In modern JavaScript, it is recommended to use let or const instead of var.
Be consistent in your use of semicolons at the end of lines.
Thus the code ends up as:
let countp = 0;
let countn = 0;
let isFinal = false;
function mapping() {
if (isFinal) {
return;
}
const num = parseInt(document.getElementById("num1").value);
let html = "";
if (Number.isNaN(num)) {
html = "invalid";
} else if (num === 0) {
html = "countp: " + countp + "<br>";
html += "countn: " + countn;
isFinal = true;
} else if (num > 0) {
html = "positive";
countp += 1;
} else {
html = "negative";
countn += 1;
}
document.getElementById("output").innerHTML = html;
}

How do I use innerHTML inside a loop using JavaScript?

Here is the code and snippet:
var amount = prompt("How many list items would you like?");
if(isNaN(amount) || amount < 1) {
alert("Please enter a positive whole number");
} else {
for(i = 0; i <= amount; i++) {
document.getElementById("content").innerHTML = "Loop: " + i + "<br>";
}
}
<div id="content"></div>
Hi, I'm a new to Javascript and I can't figure this out. How can I write into the div tag "content" using the loop to display values inside the div tag per loop?
Change to += instead of = and start the for loop with 1 unless you want to print out as loop 0, loop 1 and so on...
document.getElementById("content").innerHTML += "Loop: " + i + "<br>";
var amount = prompt("How many list items would you like?");
if(isNaN(amount) || amount < 1) {
alert("Please enter a positive whole number");
} else {
for(i = 1; i <= amount; i++) {
document.getElementById("content").innerHTML += "Loop: " + i + "<br>";
}
}
<div id="content"></div>
Your code looks basically correct but you need to understand the context in which a browser executes javascript. For a given computation (event), the browser usually executes all of that computation before it does any redraws of the actual page. What this means in your case is that only the last value of innerHTML will be used. One approach to this is to accumulate the entire innerHTML value before returning (I see IsabelHM just posted that). The second would be to use something like setTimeout to spread the computation out over multiple "sessions" - something like
var i = 0;
count = function() {
document.getElementById("content").innerHTML = "Loop: " + i + "<br>";
i++;
if (i < amount) {
window.setTimeout(count, 100);
}
};
count();
Note - I haven't run that but the idea is there. I basically count at 100ms intervals.

Treating numbers as strings

I got bored and decided to make a script, but it isn't working. Instead of adding the numbers, it treats them as strings, ex. 0 + 42 + 0 + 17 would be 042017. Also, the while script goes on forever.
var money = 0;
var yn = false;
var bye = 0;
var add = window.prompt("How many dollars do you want?");
console.log("You got " + add + " dollars!");
parseFloat(add);
money += add;
add = 0;
console.log(money);
while (money < 1000000001 || bye == 1) {
yn = window.confirm("Do you want more money?");
if (yn) {
add = window.prompt("How many dollars do you want?");
console.log("You got " + add + " dollars!");
parseFloat(add);
money += add;
console.log(money);
} else {
console.log("Goodbye!");
bye = 1;
};
};
if (money > 999999999) {
console.log("You won the game with " + money + " dollars!");
};
When you do
parseFloat(add);
it converts add to a floating point value and returns it. Since you are ignoring it, add remains unchanged as a string. You might want to replace the new value in add, like this
add = parseFloat(add);
Also, you can just convert the result of window.prompt itself, like this
add = parseFloat(window.prompt(...));
Most likely the reason your while loop is going on forever is because of the bye variable. Your logic is broken.
If the user answers No to the prompt, bye will be set to 1 and never change back. The while loop will continue as long as bye is 1, so it will go on forever.
To fix this, you can use:
while (money < 1000000001 && bye !== 1) {
or
while (money < 1000000001 || bye === 0) {
However, to store an on/off flag, you should be using a boolean variable, not a number:
var bye = false;
// ....
while (money < 1000000001 && !bye) {
// ....
if (yn) {
// ....
} else {
// ....
bye = true;
}
}
Also note that you don't need (read: shouldn't use) a semicolon after if and while blocks.

Categories

Resources