Understanding While Loop
I am trying to understand what exactly happens when I use the 'while loop' to execute a code multiple times.
I was solving a problem on JSHero.net and I found it confusing so I tried explaining the solution to myself in order to get a clear understanding.
Please study the question, the answer and the simple explanation and let me know if I have understood it correctly. I could have done better explaining the counter as using it inside the condition itself confused me a lot.
Thanking all the good people in advance for helping me !!
Stay Safe !!
Question
Write a function spaces that takes a natural number n and returns a string of n spaces.
Example: spaces(1) should return ' '.
Answer
function spaces(num) {
let mySpaces = '';
while (num-- > 0)
mySpaces += ' ';
return mySpaces;
};
Explanation
declare a function spaces
it has 1 parameter 'num'
declare a variable mySpaces
initialize it with an empty string
we use a while loop as we need to repeat an action multiple times
in this case we need to add blank spaces to a string
our '''empty spaces string''' will be stored in the variable mySpaces
blank spaces will be equal to the 'num' parameter, which is fed when the function 'spaces' is called
while loops have: a condition and a code (loop body)
our condition is to ensure that the code should execute as long as the num is greater than 0
our condition is (num-- > 0)
our code is: mySpaces += ''
so if our function is called with the following parameter then how would this while loop work
spaces (3)
first it will check if 3 > 0; which it is and it will execute the code
mySpaces = mySpaces + ' '; the result in variable mySpace will now be ' ' (1 space)
then since we have used the num as a counter (num--), the loop will reduce 1 from 3 = 2
it will check if 2 > 0; which it is and it will execute the code
mySpaces = mySpaces + ' '; the result in variable mySpace will now be ' ' (2 spaces)
then since we have used the num as a counter (num--), the loop will reduce 1 from 2 = 1
it will check if 1 > 0; which it is and it will execute the code
mySpaces = mySpaces + ' '; the result in variable mySpace will now be ' ' (3 spaces)
then since we have used the num as a counter (num--), the loop will reduce 1 from 1 = 0
it will check if 0 > 0; which it is not and it will only execute the code after the while loop
we return the mySpaces variable which will give us the final result
While construction in javascript and most popular programming language consists of these parts:
while keyword
condition inside parentheses (num-- > 0)
body (mySpaces += ' ';)
It it used to repeatedly execute statements inside the body as long as condition is true.
For example this is how would you print Hello world repeatedly 5 times (please note, for this example for loop would have been more appropriate):
i = 5;
while (i > 0) { // as long as i is above zero
console.log("Hello world"); // print 'Hello world'
i--; // decrease value of i by one
}
In this particular example execution of while loop could be described as this:
check if condition is true
if not - skip body and continue with next statement after body
if yes - execute every statement inside body once and repeat this step
It is possible based on the condition that body gets executed zero, one, or multiple times.
In your code you start with some value of num, when you enter while loop, condition is checked, it is determined, whether body should or should not be executed and then num is decreased by one (because of the -- operator). This process repeats as long as num is above zero.
Slight modification in the order:
...
<> spaces (3)
<> a variable mySpaces will be declared and initialized with an empty string literal.
<> first it will check if 3 > 0; which it is and it start the loop. The value of num has already decreased by 1 in the memory, so now num = 2.
<> mySpaces = mySpaces + ' '; the result in variable mySpace will now be ' ' (1 space)
<> it will check if 2 > 0; which it is and it will execute the code. The value of num has again decreased by 1 in the memory, so now num = 1.
<> mySpaces = mySpaces + ' '; the result in variable mySpace will now be ' ' (2 spaces)
<> it will check if 1 > 0; which it is and it will execute the code. The value of num has again decreased by 1 in the memory, so now num = 0.
<> mySpaces = mySpaces + ' '; the result in variable mySpace will now be ' ' (3 spaces)
<> it will check if 0 > 0; which is false and it will not execute the code inside the while loop anymore. The value of num has again decreased by 1 in the memory, so now num = -1.
<> The last value of mySpaces which is ' ' (3 spaces) is returned from the function.
P.S. I've tried to write the answer in a way closest to how you've explained it. Hope this clears everything! Next time if you find the flow of code confusing always remember to put print statements at different places. Putting a console.log("Checkpoint 1") or printing the value of the variables in action greatly helps one to understand the changes as they happen. A more advanced way is to put breakpoints in code and debug. OnlineGDB's IDE makes a table of values for the variables and displays them at each stop.
Related
Hello I'm trying to understand recursion in JavaScript.
So far I have:
function countVowels(string) {
let vowelCount = 0;
// if we're not at the end of the string,
// and if the character in the string is a vowel
if (string.length - 1 >= 0 && charAt(string.length -1) === "aeiouAEIOU") {
//increase vowel count every time we iterate
countVowels(vowelCount++);
}
return vowelCount;
}
First of all, this is giving me issues because charAt is not defined. How else can I say "the character at the current index" while iterating?
I can't use a for-loop - I have to use recursion.
Second of all, am I using recursion correctly here?
countVowels(vowelCount++);
I'm trying to increase the vowel count every time the function is called.
Thanks for your guidance.
If you're interested, here is a version that does not keep track of the index or count, which might illuminate more about how the recursion can be done.
function countVowels(string) {
if (!string.length) return 0;
return (
"aeiou".includes(string.charAt(0).toLowerCase()) +
countVowels(string.substr(1))
);
}
console.log(countVowels("")); // 0
console.log(countVowels("abcde")); // 2
console.log(countVowels("eee")); // 3
// Note that:
console.log('"hello".substr(1)', "hello".substr(1)) // ello
console.log('"hello".charAt(0)', "hello".charAt(0)) // h
console.log('"aeiou".includes("a")', "aeiou".includes("a")) // true
console.log('"a".includes("aeiou")', "a".includes("aeiou")) // false
Our base case is that the string is empty, so we return 0.
Otherwise, we check if the first character in the string is a vowel (true == 1 and false == 0 in javascript) and sum that with counting the next (smaller by one) string.
You are making two mistakes:
You should have three parameters string , count(count of vowels) and current index i.
You should use includes() instead of comparing character with "aeiouAEIOU"
function countVowels(string,count= 0,i=0) {
if(!string[i]) return count
if("aeiou".includes(string[i].toLowerCase())) count++;
return countVowels(string,count,i+1);
}
console.log(countVowels("abcde")) //2
As asked by OP in comments "Can you please explain why it'sif("aeiou".includes(string[i].toLowerCase())) instead of if(string[i].includes("aeiou".toLowerCase()))"
So first we should know what includes does. includes() checks for string if it includes a certain substring passed to it or not. The string on which the method will be used it will be larger string and the value passed to includes() be smaller one.
Wrong one.
"a".includes('aeiou') //checking if 'aeiou' is present in string "a" //false
Correct one.
"aeiou".includes('a') //checking if 'a' is present in string "aeiou" //true
One possible solution would be:
function countVowels(string, number) {
if (!string) return number;
return countVowels(string.slice(1), 'aeiouAEIOU'.includes(string[0])? number + 1 : number);
}
// tests
console.log('abc --> ' + countVowels('abc', 0));
console.log('noor --> ' + countVowels('noor', 0));
console.log('hi --> ' + countVowels('hi', 0));
console.log('xyz --> ' + countVowels('xyz', 0));
and you should call your function like: countVowels('abc', 0)
Notes about your solution:
you always reset vowelCount inside your function, this usually does not work with recursion.
you defined your function to accept a string, but recall it with an integer in countVowels(vowelCount++); this it will misbehave.
always remember that you have to define your base case first thing in your recursion function, to make sure that you will stop sometime and not generate an infinite loop.
Alternative ES6 solution using regex and slice() method. Regex test() method will return true for vowels and as stated in a previous answer JavaScript considers true + true === 2.
const countVowels = str => {
return !str.length ? 0 : /[aeiou]/i.test(str[0]) + countVowels(str.slice(1));
}
When I call a recursive on function, where do the results of the call go?
function reverse(str){
if (str.length == 1){
return str;
}
rev = reverse(str.substr(1)) + str.charAt(0);
}
reverse("String");
console.log(rev); // ----> "undefinedS" - Only the last call is saved.
If I just return the value it seems fine. Where is the result getting stored?
function reverse(str){
if (str.length == 1){
return str
}
return reverse(str.substr(1)) + str.charAt(0);
}
reverse("String") // ----> "gnirtS"
Your first version
rev is stored in the global namespace, and is overwritten each time the function reverse is called.
The recursion stops when the string's length is one, after having taken only the last n-1 characters. As a result, the final character is the only character in the string, S, and that is what str.charAt(0) gives.
Since the function reverse does not return a value when str is length 0 (which is what happens with "S".substr(1)) the value of reverse(str.substr(1)) is undefined.
This results in undefinedS.
Your second version
This version creates a call stack whereby the string is slowly taken apart by n-1 (where n is its length) until its length is 1. At that point the stack is unwound, causing each letter from the last to the first to be returned. Each function call as its own Execution context, whereby a Variable Environment is holding the value of each string.
The result of the callstack unwinding is gnirtS.
Cleaner Look code
function reverse(str){
return (str.length == 1)? str : reverse(str.substr(1)) + str.charAt(0);
}
I just have a question about some while loop logic.
So, when you write a loop that displays a string of numbers to a document and say that while the loop is <= (less than or equal to) say, 5, and you tell the loop to add 1 each time this is true, wouldn't that mean that: while the loop is equal to 5 that it would add one to 5 too? It doesn't, but I messed up on some code when I was practicing and noticed that when it is equal to five it does not add one, but I thought it would...
console.log('2nd Loop:');
text = '';
// loop:
i = 1;
while (i <= 5) {
text += i + ' ';
i += 1
}
console.log(text); // Should print `1 2 3 4 5 `.
the reason your text doesn't display a 6 isn't because i isn't incremented. It's because the text gets added onto before it's incremented.
In other words when executing on that 5th loop, the text would add on 5, and then it would increment i, and then it would check the loop again, which would no longer be valid and therefore 6 is never printed.
In memory, it adds one. It doesn't add it to the text though.
Since you're incrementing the value after assigning it and then the loop condition fails, it doesn't get to the part where you concatenate the string.
It does. Just output i and you'll see it's 6. text never gets the 6 because of when you increment i.
console.log('2nd Loop:');
text = '';
// loop:
i = 1;
while (i <= 5) {
text += i + ' ';
i += 1
}
console.log(text,i); // Should print `1 2 3 4 5 `.
b/c you +1 after you add i to text, all you need to do is switch the two line order.
EDIT
if you want it start with one just change your i to 0 to start with.
i = 1
console.log('2nd Loop:');
text = '';
i = 0;
while (i <= 5) {
i += 1
text += i + ' ';
}
console.log(text);
I have a variable declared here:
var quizScore = 0;
And I want to add a number to it each time the correctAnswer() function runs:
function correctAnswer(){
quizScore+1;
console.log ( 'correct answer selected: quizscore = ' + quizScore );
}
I added a console log for debugging. It works, so the function is being called, but it is not adding the score. Do I need to parse this to an integer? I can't work out what the +1 needs to be to work correctly.
You can go here and you will see that clicking "Lightning Bolt" for question 1 shows "correct answer" in the console, but doesn't add to the score variable.
Do it like this:
function correctAnswer(){
console.log ( 'correct answer selected: quizscore = ' + (++quizScore) );
}
You just need to assign the +1 to quizScore variable. This may be the fastest way to add 1 and display it in one line
You're adding one to whatever value is in quizScore, and doing nothing with the result.
You need quizScore = quizScore + 1.
Keep quizscore as global variable.
And secondly change the line no.1 of your correctAnswer() function to
quizScore = quizScore + 1;
You can use self-memorizing function not to pollute global environment with variables like so:
function correctAnswer() {
correctAnswer.quizScore = (correctAnswer.quizScore || 0) + 1;
console.log("QuizScore : " + correctAnswer.quizScore);
}
for (var i = 0; i < 10; i++) {
correctAnswer(); // output 1 2 3 4 5 6 7 8 9 10
}
Right now, when you do this:
quizscore+1;
You add one to it but it doesn't assign the change to the variable. One reason for this is that sometimes you may want to add a number to the variable long enough to perform an operation but you don't want it to change.
// quiz score is left alone
var nextscore = quizscore + 1
Here are the different ways to actually assign it:
// temporarily adds 1 to quizscore, then saves it to quizscore
quizscore = quizscore + 1
// adds one to quizscore after it's used in an expression
quizscore++
// adds one to quizscore before it's used in an expression
++quizscore
So if you did something like this:
var nextscore = ++quizscore + 1;
You would both increment the current score and predict the next score.
Read more: Expressions and Operators
Why this code outputs 3, not 2?
var i = 1;
i = ++i + --i;
console.log(i);
I expected:
++i // i == 2
--i // i == 1
i = 1 + 1 // i == 2
Where I made mistake?
The changes occur in this order:
Increment i (to 2)
Take i for the left hand side of the addition (2)
Decrement i (to 1)
Take i for the right hand side of the addition (1)
Perform the addition and assign to i (3)
… and seeing you attempt to do this gives me some insight in to why JSLint doesn't like ++ and --.
Look at it this way
x = (something)
x = (++i) + (something)
x = (2) + (something)
x = (2) + (--i)
x = (2) + (1)
The terms are evaluated from left to right, once the first ++i is evaluated it won't be re-evaluated when you change its value with --i.
Your second line is adding 2 + 1.
In order, the interpreter would execute:
++i // i == 2
+
--i // i == 1
i = 2 + 1
++i equals 2, `--i' equals 1. 2 + 1 = 3.
You're a little off on your order of operations. Here's how it goes:
i is incremented by 1 (++i) resulting in a value of 2. This is
stored in i.
That value of two is then added to the value of (--i)
which is 1. 2 + 1 = 3
Because when you use ++i the value of i is incremented and then returned. However, if you use i++, the value of i is returned and then incremented. Reference
++$a Increments $a by one, then returns $a.
$a++ Returns $a, then increments $a by one.
--$a Decrements $a by one, then returns $a.
$a-- Returns $a, then decrements $a by one.
Because you're expecting this code to work as if this is a reference object and the values aren't collected until the unary operations are complete. But in most languages an expression is evaluated first, so i returns the value of i, not i itself.
If you had ++(--i) then you'd be right.
In short, don't do this.
The result of that operation isn't defined the same in every language/compiler/interpreter. So while it results in 3 in JavaScript, it may result in 2 elsewhere.