Getting the condition of a while loop to print out once false - javascript

I am doing an exercise on an online course to learn Javascript. This is only the first one and I am having issues, so I really want to understand it before I progress.
The question is this:
complete the while loop in the editor so it will print out "I'm learning while loops!". Do this by adding the condition between the parentheses—don't change line 5, or you could get an infinite loop!
The code is:
var understand = true;
while(){
console.log("I'm learning while loops!");
understand = false;
}
I tried adding this to the condition:
while(understand === 0){
But I am getting this error
Oops, try again. It looks like you didn't print the string to the console. Check your loop syntax!
What am I doing wrong in my condition? Could someone please elaborate, so I can learn the key fundamentals to this. Thanks!
The example before this exercise:
var coinFace = Math.floor(Math.random() * 2);
while(coinFace === 0){
console.log("Heads! Flipping again...");
var coinFace = Math.floor(Math.random() * 2);
}
console.log("Tails! Done flipping.");
Edit---update:
You may have noticed that when we give a variable the boolean value true, we check that variable directly—we don't bother with ===. For instance,
var bool = true;
while(bool){
//Do something
}
is the same thing as
var bool = true;
while(bool === true){
//Do something
}
but the first one is faster to type. Get in the habit of typing exactly as much as you need to, and no more!
If you happen to be using numbers, as we did earlier, you could even do:

It's while(understand === true)
Because the loop will fire the first time, as understand is already set to true. Then, as it's firing, it will set understand to false- so the next time it tries to fire the loop the condition will fail and it won't continue. This way, you're getting one execution of the loop- thus printing only one time.

If you had code that looks like this
while(true){
console.log("I'm learning while loops!");
understand = false;
}
you would get an infinite loop! The loop would just keep going because the conditional will always be true. Now if only there were some way, like a variable in the conditional, to make the conditional false.

Related

basic Javascript While loop and boolean value questions

I would ask my instructor, but whenever I do, he gives me an even more vague answer to my questions, so I'm asking yall for help. We "learned" (i.e. watched videos) about for and while loops and I get it, I feel like I do, but whenever it comes to doing the assignments given, I feel like they don't make sense. Like back in math class in high school, they'd teach you about the problems, but then when it came time to do your homework, the problems were completely different from what you just learned about. For instance, it says the basic while loop structure is:
while(condition is true) {
//do something
}
But then in this assignment, it gives me:
// Another way to write a while loop is to have a boolean variable
// where the condition goes and then test every time if you need to
// change the boolean to false.
// Below we have a variable lessThan5 and it is set to true.
// Create a loop that tests if our variable 'j' is less than 5.
// If it is less than 5 then Increment it by 1. If it is not
// less than 5 then set our lessThan5 variable to be false.
let lessThan5 = true;
let j = 0;
while(lessThan5) {
}
We didn't learn anything about using boolean values in while loops and I feel like I'm meant to infer what to do, and what structure to use and I just have no idea. Aside from the fact I feel like the instructions to many of these questions are poorly worded, which only confuses me more!
So then there's this third one:
// Example of what the number game would look like:
// Couple things to note:
// Math is a built in object in javascript.
// Math.round() will round a decimal number to a whole number.
// Math.random() returns a decimal number between 0 to 1.
// (But not including 1)
function guessNumberGame(guess) {
let guessing = true;
let number = Math.round(Math.random() * 100);
while(guessing) {
if(guess === number) {
guessing = false;
} else {
guess = Number(prompt("That number didn't work. Try again: "));
}
}
}
// Problem 3
// We will give you a number through the 'num' parameter
// Create a while loop that will loop 'num' amount of times.
// For example if num is 3 then your while loop should loop 3 times
// If num is 20 then the loop should loop 20 times.
// Increment k every loop.
let k = 0;
function keepLooping(num) {
}
If this Problem 3 is meant to be related somehow to the number game example, I can't see it. I don't even know what it is I need to be asking. Does this make any sense to anyone? And nobody else is publicly asking questions about any of this, and it's making me feel stupid and like I am the only one too dumb to get what's going on. I was doing really well and ahead of schedule with all this until this point, but just none of this is making any sense to me.
Welcome to programming, JavaScript (JS), and StackOverflow (SO)!
Let's dive into this a little deeper. First, a quick JavaScript primer: in JavaScript, everything can be classified as either an expression or a statement. At a super high and not-technical level:
expression: something that produces a value
statement: an instruction to the computer
(For a much longer explanation, see here)
Often, statements have slots that can take expressions. Loops are a great example of that.
For example, 1 + 1 is an expression, since it produces the value 2. Even more simply, 1 on its own is also an expression, since it produces the value 1. while(/*some expression here*/) is a statement that has a slot for an expression. for(s1, e2, e3) is also a statement that has slots for statements and slots.
So, the while loop acts on an expression, and will continue to loop as long as the value returned by that expression is truthy. truthy and falsey is an interesting concept in JavaScript and can be a whole essay on it's own, but the tl;dr of it is that anything that == true is truthy, and anything that == false is falsey
So for your first question, 0 < 5 == true, while 5 < 5 == false. Thus, if you make the value of j be greater than or equal to 5, the loop will break.
let lessThan5 = true;
let j = 0;
while(lessThan5) {
// For each cycle of the loop, check if `j` is less than 5
if (j < 5) {
// If `j` is less than 5, increment it
j++; // This is equivalent to saying j = j + 1, or j += 1
} else {
// If `j` is not less than 5, set `lessThan5` to `false`
// Not when the loop goes to iterate again, `false == false`, and it stops
lessThan5 = false;
}
}
I think given the above you should be able to solve the third problem. Please let us know if you have trouble with it, show us what you try, and we'll be happy to help some more :)
Let's take a deep breath and relax. I'm a very senior developer and can't tell -- from your examples -- what's going on here. Maybe that's because your instructor is terrible, maybe it's because you've missed some context in your class, and so it's omitted from the question.
I can answer the two questions you've been given. Hopefully it'll be helpful.
First:
I do not know why your materials claim that a while loop might be written this way. I've completed the assignment, but it seems very odd. But if they want you to complete it, here's a solution.
// Another way to write a while loop is to have a boolean variable
// where the condition goes and then test every time if you need to
// change the boolean to false.
// Below we have a variable lessThan5 and it is set to true.
// Create a loop that tests if our variable 'j' is less than 5.
// If it is less than 5 then Increment it by 1. If it is not
// less than 5 then set our lessThan5 variable to be false.
let lessThan5 = true;
let j = 0;
while(lessThan5) {
if (j >= 5) {
lessThan5 = false;
} else {
j++;
}
}
Moving on to the second snippet, the second snippet does not, to me, appear to be related to guessNumberGame in any way.
And the solution to "Problem 3" seems useless to me. A loop that doesn't do anything is not useful in real life.
That said, the solution to "Problem 3" is as follows:
// Problem 3
// We will give you a number through the 'num' parameter
// Create a while loop that will loop 'num' amount of times.
// For example if num is 3 then your while loop should loop 3 times
// If num is 20 then the loop should loop 20 times.
// Increment k every loop.
let k = 0;
function keepLooping(num) {
while(k < num) {
k++;
}
}

How to change an objects properties right after a condition is met?

I am trying to make a button go from .disabled = true to .disabled = false. I am making a Yahtzee clone for fun, and you have to choose a score to take on your third roll, and then after that the button will be unlocked and you can roll again. Here's what I had, but it crashes. I wanted to make a while statement until a score is selected. ptsss is the amount of scores that have been selected. (i.e. third roll should equal 1 score entered)
if(rollcount == 3){
while (ptsss * 3 < rollcount){
document.getElementById("rollbutton").disabled = true;
if (ptsss * 3 == rollcount){
document.getElementById("rollbutton").disabled = false;
break;
}
}
}
}
Try removing the while loop and (possibly) rewrite the code as a function to enable/disable the roll button as required. E.G.
function checkRollButton( rollcount, ptsss) {
if(rollcount == 3) {
document.getElementById("rollbutton").disabled = ptsss != 1;
}
}
Then call (or inline the code for) checkRollbutton in event handlers that update rollcount and/or ptsss.
As commented, the value of ptsss cannot be changed by other code while the while loop is running, because JavaScript is single threaded.
I've modified the statement that enables/disables the roll button according to my understanding of the design, please check it before use.
Loops in JavaScript are not like loops in some other languages.
If the condition in the loop is not being modified within the loop itself, it won't be modified (unless possibly it's happening inside an asynchronous function).
Also you shouldn't constantly use the getElement in a loop anyways.
The way to achieve the general functionality of what a while loop is in other languages, in JavaScript, is to use an interval.
So based on that your updated code can look something like this (not sure where the first if statement is being called from so I took it out, also the nested if statement would have never been called because it only takes effect if it's condition is false, so I changed that as well):
var roll=document.getElementById("rollbutton")//make sure this is called after that element has loaded
var inter=setInterval(function(){
if (ptsss * 3 == rollcount){
roll.disabled = false;
clearInterval(inter)
//Similar to break in while loop, can restart interval later after this
}
if (ptsss * 3 < rollcount){
roll.disabled = true;
}
}
},1000/30//30 FPS
);

Why is my script saying '(' === ')' is true?

I was doing this kata on codewars. The question wants the function to return true if the first argument (string) passed in ends with the 2nd argument (also a string). So I wrote my function and everything worked just fine until it compares ':-)' with ':-(' and returns true.
What is wrong? I'm so confident that my code should work that I don't even know what to search for.
function solution(str, ending){
if (!ending) return true; // if ending is a empty string return true (the question wants that)
let ok;
const strArr = str.split(''), endingArr = ending.split('');
for (let i = 0; i < endingArr.length; i++) strArr.reverse()[i] === endingArr.reverse()[i] ? ok = true : ok = false;
return ok;
}
console.log(solution(":-)",":-("));
Your problem is a misunderstanding of what reverse() does. It does not return a reversed copy of the old array, it reverses the existing array and returns that same array. As a result, you keep reversing the arrays back and forth every iteration of the loop, causing some elements to be skipped and some to be checked twice.
Array.prototype.reverse() on MDN
Edit:
As pointed out by others in the comments, both to the question and this answer, there are in fact multiple problems.
reverse() aside, the loop always sets ok to the result of the last comparison, making the function ignore all previous results.
The easier way to implement this is to remove ok altogether. Instead, return false as soon as a mismatch is detected. If the function runs long enough to exit the loop, it means no mismatch was detected and true can be returned.
Edit 2:
Just as a friendly suggestion:
While both reverse() and ok are real issues with the code, I only noticed the first one the first time around due to the formatting of the code. The ok problem was off-screen due to the line being too long. As such, once I spotted the reverse() issue, I assumed that was it and didn't bother scrolling sideways to see the rest of the code.
I am not going to demand that you write your own code in a certain way, but if you format it properly, it allows others to read it more easily. In essence, you help us to more easily help you.
For instance, this line:
for (let i = 0; i < endingArr.length; i++) strArr.reverse()[i] === endingArr.reverse()[i] ? ok = true : ok = false;
...would have been significantly easier to read as...
for (let i = 0; i < endingArr.length; i++) {
if(strArr.reverse()[i] === endingArr.reverse()[i])
ok = true;
else
ok = false;
}
...or some variation thereof. Here, the problem is significantly more visible and obvious.
The other answer explains many of the mistakes you've made. I wanted to point out just how much you've over-thought your solution.
function solution(str, ending){
if (ending === "") return true; // if ending is a empty string return true (the question wants that)
return str.endsWith(ending);
}
console.log(solution(":-)",":-("));
console.log(solution("foo",""));
console.log(solution("foo","bar"));
console.log(solution("foobar","bar"));
Even my solution above is overengineered, str.endsWith("") always returns true. So this can be simplified further.
function solution(str, ending){
return str.endsWith(ending);
}
console.log(solution(":-)",":-("));
console.log(solution("foo",""));
console.log(solution("foo","bar"));
console.log(solution("foobar","bar"));

Javascript code causing IE freeze

I have the below code causing Internet Explorer to freeze. It's a project that involves processing student grades as an assignment:
var array1 = StudentGradeAreadHugeList();
var nextArrayItem = function() {
var grade = array1.pop();
if (grade) {
nextArrayItem();
}
};
i hope you can help me with this.
You could show more info about the application you're trying to do. But I believe it's a matter of stack overflow (maybe you're using a big list). So, to overcome that you should modify the "nextArrayItem":
window.setTimeout (nextArrayItem, 0)
The freeze incurring mainly from the big data, but now the Event Loop will handle the Recursion process and not your Call Stack.
This is likely caused by an endless recursion. Be aware of proper handling of return values in IE:
var array1 = StudentGradeAreadHugeList();
var nextArrayItem = function() {
var grade = array1.pop();
if ( grade !== null && typeof(grade) !== "undefined" ) {
nextArrayItem();
}
};
pop() on an empty array will not return boolean false but a typeless "undefined".
There's two problems here:
You might be exceeding the call stack limit
Your if-conditional is set-up incorrectly
For the first issue:
As one of the previous responders mentioned, if you have a very large list you can exceed the limit of the call stack since you need to do a recursive call for each element. While doing setTimeout might work, it feels like a hack-y solution. I think the real issue is that your function is handling the array recursively rather than iteratively. I would recommend re-writing your function using a for-loop.
For the second issue:
Let's say in this case your array was set to [100, 90, 80]. When you invoke nextArrayItem() it will work properly the first two time, but the third time you call nextArrayItem() you are popping off the last remaining item (in this case 100) and your grade will be set to 100 which is a truthy value. Therefore, your if-conditional will pass and your function erroneously try to invoke itself again despite the fact that your array is now empty and the program should now exit the call stack.
I tried testing your code using my example in Chrome and what happens is that it will recurse one too many times and invoke pop on an empty array, which will return undefined.
You can fix this issue by changing the if conditional to check for the last element in the array after you have popped the array.
See revised code:
var nextArrayItem = function() {
var grade = array1.pop();
if (array1[array1.length-1]) {
nextArrayItem();
}
};

Programming optional ignorance

In Javascript what is the best way to handle scenarios when you have a set of arrays to perform tasks on sets of data and sometimes you do not want to include all of the arrays but instead a combination.
My arrays are labeled in this small snippet L,C,H,V,B,A,S and to put things into perspective the code is around 2500 lines like this. (I have removed code notes from this post)
if(C[0].length>0){
L=L[1].concat(+(MIN.apply(this,L[0])).toFixed(7));
C=C[1].concat(C[0][0]);
H=H[1].concat(+(MAX.apply(this,H[0])).toFixed(7));
V=V[1].concat((V[0].reduce(function(a,b){return a+b}))/(V[0].length));
B=B[1].concat((MAX.apply(this,B[0])-MIN.apply(this,B[0]))/2);
A=A[1].concat((MAX.apply(this,A[0])-MIN.apply(this,A[0]))/2);
D=D[1].concat((D[0].reduce(function(a,b){return a+b}))/(D[0].length));
S=S[1].concat((S[0].reduce(function(a,b){return a+b}))/(S[0].length));
}
It would seem counter-productive in this case to litter the code with tones of bool conditions asking on each loop or code section if an array was included in the task and even more silly to ask inside each loop iteration with say an inline condition as these would also slow down the processing and also make the code look like a maze or rabbit hole.
Is there a logical method / library to ignore instruction or skip if an option was set to false
All I have come up with so far is kind of pointless inline thing
var op=[0,1,1,0,0,0,0,0]; //options
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
op[0]&&[L[0]=1];
op[1]&&[C[0]=1,console.log('test, do more than one thing')];
op[2]&&[H[0]=1];
op[3]&&[V[0]=1];
op[4]&&[B[0]=1];
op[5]&&[A[0]=1];
op[6]&&[A[0]=1];
It works in that it sets only C[0] and H[0] to 1 as the options require, but it fails as it needs to ask seven questions per iteration of a loop as it may be done inside a loop. Rather than make seven versions of the the loop or code section, and rather than asking questions inside each loop is there another style / method?
I have also noticed that if I create an array then at some point make it equal to NaN rather than undefined or null the console does not complain
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
L=NaN;
L[0]=1;
//1
console.log(L); //NaN
L=undefined;
L[0]=1
//TypeError: Cannot set property '0' of undefined
L=null
L[0]=1
//TypeError: Cannot set property '0' of null
Am I getting warmer? I would assume that if I performed some math on L[0] when isNaN(L)===true that the math is being done but not stored so the line isn't being ignored really..
If I understand what you want I would do something like this.
var op = [...],
opchoice = {
//these can return nothing, no operation, or a new value.
'true': function(val){ /*operation do if true*/ },
'false': function(val){ /*operation do if false*/ },
//add more operations here.
//keys must be strings, or transformed into strings with operation method.
operation: function(val){
//make the boolean a string key.
return this[''+(val == 'something')](val);
}
};
var endop = [];//need this to prevent infinite recursion(loop).
var val;
while(val = op.shift()){
//a queue operation.
endop.push(opchoice.operation(val));
}
I'm sure this is not exactly what you want, but it's close to fulfilling the want of not having a ton of conditions every where.
Your other option is on every line do this.
A = isNaN(A) ? A.concat(...) : A;
Personally I prefer the other method.
It looks like you repeat many of the operations. These operations should be functions so at least you do not redefine the same function over and over again (it is also an optimization to do so).
function get_min(x)
{
return +(MIN.apply(this, a[0])).toFixed(7);
}
function get_max(x)
{
return +(MAX.apply(this, a[0])).toFixed(7);
}
function get_average(x)
{
return (x[0].reduce(function(a, b) {return a + b})) / (x[0].length);
}
function get_mean(x)
{
return (MAX.apply(this, x[0]) - MIN.apply(this, x[0])) / 2;
}
if(C[0].length > 0)
{
L = L[1].concat(get_min(L));
C = C[1].concat(C[0][0]);
H = H[1].concat(get_max(H));
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A);
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
You could also define an object with prototype functions, but it is not clear whether it would be useful (outside of putting those functions in a namespace).
In regard to the idea/concept of having a test, what you've found is probably the best way in JavaScript.
op[0] && S = S[1].concat(get_average(S));
And if you want to apply multiple operators when op[0] is true, use parenthesis and commas:
op[3] && (V = V[1].concat(get_average(V)),
B = B[1].concat(get_mean(B)),
A = A[1].concat(get_mean(A));
op[0] && (D = D[1].concat(get_average(D)),
S = S[1].concat(get_average(S)));
However, this is not any clearer, to a programmer, than an if() block as shown in your question. (Actually, many programmers may have to read it 2 or 3 times before getting it.)
Yet, there is another solution which is to use another function layer. In that last example, you would do something like this:
function VBA()
{
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A));
}
function DS()
{
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
op = [DS,null,null,VBA,null,null,...];
for(key in op)
{
// optional: if(op[key].hasOwnProperty(key)) ... -- verify that we defined that key
if(op[key])
{
op[key](); // call function
}
}
So in other words you have an array of functions and can use a for() loop to go through the various items and if defined, call the function.
All of that will very much depend on the number of combinations you have. You mentioned 2,500 lines of code, but the number of permutations may be such that writing it one way or the other will possibly not reduce the total number of lines, but it will make it easier to maintain because many lines are moved to much smaller code snippet making the overall program easier to understand.
P.S. To make it easier to read and debug later, I strongly suggest you put more spaces everywhere, as shown above. If you want to save space, use a compressor (minimizer), Google or Yahoo! both have one that do a really good job. No need to write your code pre-compressed.

Categories

Resources