How to restructure .forEach so I can break out of it - javascript

I have had a lot of trouble with JavaScript and 'break' statements coming from a Ruby background.
Here is my function:
function isItTheNumber(numberToGuess){
if(previousGuess === null){
previousGuess = [playersGuess];
}
previousGuess.forEach(function(guess){
if(playersGuess === guess && previousGuess > 1){
textStatus.style.display = 'block';
textStatus.innerHTML = 'You already picked that number';
} else if(parseInt(playersGuess) === parseInt(numberToGuess)){
textStatus.style.display ='block';
textStatus.innerHTML = 'You Are CORRECT!';
} else {
previousGuess.push(playersGuess);
textStatus.style.display='block';
textStatus.innerHTML = 'You are ' + hotOrCold();
document.getElementById('guess-count').innerHTML = playerGuessCount++;
}
});
}
In my .forEach loop I would like to have a 'break' statement in my first if statement. I would like the loop to stop if it ever executes this block.
I realize I can't use a break statement in this forEach function after reading a few posts about it. I attempted the suggestion here using "every" but when I was using this wrapped in a function I was not able to return a true or false value.
I would like to avoid having to use any type of 'break' or hack for the break but will use it if it is the only way. If anyone has any suggestions on how I can re-work my logic or have any suggestions I would appreciate it. I'll list my logic in pseudo code below.
1) Check if the previousGuess array is null or populated. If it is null, set it to an array with the first value.
2) Iterate over the previousGuess array.
3) If: see if the user input (playerGuess) is in the previousGuess array. The previous guess
array must be larger than 1.
4) Else If: If the users guess is the same as the a the value, tell them they are correct.
5) Else: if the users guess isn't the same as the value, tell them and add 1 to the playerGuessCount.
The problem with my current logic is that the playerGuessCount is being invoked too many times. If the array is being iterated over and finds and the first if statement is true, it will still iterate over the rest of the array, adding 1 to the playerGuessCount even when they only submit 1 guess. The .forEach is strictly there to check if their guess is a repeat.
Here is my attempt with 'every' http://repl.it/P74

The .forEach method you are using is a wrapper implemented by extending a function prototype.
You can break out of a conventional loop:
for (var key in objs){
var obj=objs[key];
//do your business here
break; //this line exists the loop
}
However, if a callback function is used, you have to terminate the function call itself by placing a "skip" variable.
previousGuess.forEach(function(guess){
if (this.skip_the_foreach_loop) return;
if (need_to_exit) this.skip_the_foreach_loop=true;
});
Not the most efficient way but saves you a few CPU cycles.

Would this work for what you're trying to do?
function isItTheNumber(numberToGuess){
if(previousGuess === null){
previousGuess = [playersGuess];
}
// Using Array.prototype.every so a falsey return breaks
previousGuess.every(function(guess){
if(playersGuess === guess && previousGuess > 1){
textStatus.style.display = 'block';
textStatus.innerHTML = 'You already picked that number';
return; // returns undefined which is falsey and breaks loop.
} else if(parseInt(playersGuess) === parseInt(numberToGuess)){
textStatus.style.display ='block';
textStatus.innerHTML = 'You Are CORRECT!';
} else {
previousGuess.push(playersGuess);
textStatus.style.display='block';
textStatus.innerHTML = 'You are ' + hotOrCold();
document.getElementById('guess-count').innerHTML = playerGuessCount++;
}
return true; // Meaning go to next iteration
});
}

Related

JavaScript for loop issue affects guess count

so I'm trying to build a JavaScript hangman game and I'm having a problem with my checkMatch function. what I'm trying to achieve is for it to check against the hiddenChoice array and only run the code in the else if statement if this.id isn't in the array at all. currently if hiddenChoice = apple and this.id = l it will return 'guess again' 3 times before it returns that 'you found a letter' when it hits l, which affects my guess count. All of the console.logs are in there so I could figure out what was going on. thanks for the help.
function checkMatch(){
console.log(hiddenChoice)
for (let k = 0; k < hiddenChoice.length; k++){
if (this.id === hiddenChoice[k]){
console.log('you found a letter')
console.log(this.id)
greenColor = this.id
green(greenColor)
right++
console.log(right)
return
}
else if (this.id != hiddenChoice[k]) {
console.log('guess again')
console.log(guesses)
console.log(this.id)
redColor = this.id
red(redColor)
guesses--
}
}
The else shouldn't be inside the loop, because you cannot yet know whether any of the next characters would match. Only when the loop has finished you know that none of the letters matched.
So:
function checkMatch(){
console.log(hiddenChoice)
for (let k = 0; k < hiddenChoice.length; k++){
if (this.id === hiddenChoice[k]){
console.log('you found a letter')
console.log(this.id)
greenColor = this.id
green(greenColor)
right++
console.log(right)
return
}
}
console.log('guess again')
console.log(guesses)
console.log(this.id)
redColor = this.id
red(redColor)
guesses--
}
Some other remarks:
Your code uses several variables which are not declared, or at least global. This should be avoided. Declare temporary variables (like greenColor?) as local variables (e.g. with let).
End your statements with a semi-colon. JavaScript does this automatically when you don't, using some rules, but you don't want that to happen as there are some pitfalls.
It is not clear what this is. It would be better if id were passed as argument to the function.
Your code will not work as expected if a single guess has multiple matches. Try to think how you could manage that (as an exercise).

issues with localStorage and saving values

I have a program where I have these strings being added to an array. However, there are many strings that are triggered by a certain condition, which can be met multiple times, however I only want it to be added on the first occurrence. So I have implemented a system where the event of adding the string to the array is triggered by the original condition, and a boolean expression. Here is an example of one of those conditions:
if (count >= 10 && displayMulti == true) {
consoleData.shift()
consoleData.push("Multi available")
displayMulti = false
window.localStorage.setItem("display_multi", String(displayMulti))
updateConsole()
}
When the string is added to the array, the boolean, displayMulti, is set to false so that it will not trigger again. However, upon refreshing the page, it will still trigger. I'm not sure why because I feel like I have saving the values to localstorage correctly. Code is below:
if (window.localStorage.getItem("display_multi") != null ) {
displayMulti = Boolean(window.localStorage.getItem("display_multi"))
} else {
console.log("here")
var displayMulti = true
}
There "here" console log statement is not triggered. So I have no idea why this would keep triggering because I don't see how the boolean is true. I've tested at like so many different points I genuinely have no idea what's wrong. I also don't think those values are affected anywhere else in my code. Any help is appreciated.
Here is a solution that properly parses your string as a boolean. Instead of Boolean(), a conditional (window.localStorage.getItem("display_multi") === 'true')(window.localStorage.getItem("display_multi") === 'true') is used.
if (window.localStorage.getItem("display_multi") != null ) {
displayMulti = (window.localStorage.getItem("display_multi") === 'true')
} else {
console.log("here")
var displayMulti = true
}
if (count >= 10 && displayMulti == true) {
consoleData.shift()
consoleData.push("Multi available")
displayMulti = false
window.localStorage.setItem("display_multi", String(displayMulti))
updateConsole()
}

Conditions proof confusing

Given is res[]:
for(let k = 0; k < res.length; k++){
if($("#getData").val().length == 20){
//if ((res[k]) != $("#getData").val()) helpText = "No match!";
// -- Tried this too and a several other options - foreach, else, else if e. g.
if(!((res[k]) == $("#getData").val()))
resText = "No match!";
if((res[k]) == $("#getData").val())
resText = "Success!";
$("#result").html(resText);
}
}
If the !((res[k]) == $("#getData").val()) - "false" condition is defined, it always only makes the first res[0] item within the array valid. This item is possible to proof correctly - The array donĀ“t iterate.
If the - "false" condition is not defined, all works fine if only the "true" condition is defined. But in this way there is no resText == "No match!";
What is wrong...?
As #charlietfl mentioned, you are looping across an array and updating the result text at each index. Because you are never stopping the looping process, what this really means is that you are only ever getting the result from the last item in the array. If your "Success!" value is item 14 in a 20 item array, your result will match and pass on that iteration, but then will be overwritten on the iterations for the next 5 items. If the very last item is a success condition you will always get "Success!" and if not you will always get "No match!" regardless of the other items in the list.
My assumption is that what you are looking to do is determine if one of the items in the array is a match, and if so you want "Success!" as the output. If so, I suggest:
const success = false;
const getDataVal = $("#getData").val();
if (getDataVal.length == 20) {
for(let k = 0; k < res.length; k++) {
if (res[k] == getDataVal) {
success = true;
break;
}
}
}
$("#result").html(success ? "Success!" : "No match!");
I restructured your code a bit here to help me understand it. Note that I did some optimizations to it:
Moved the $("#getData").val() operation out of the loop and stored to a variable since the value will not change. This simplifies the code and is much easier on the processor.
Moved the condition on the length check of the value outside the loop. The loop contents would only ever run whenever that condition is true, so it is better to wrap the loop in the condition so that it never runs at all if that condition fails.
Added a break; to the loop to stop the loop once a success condition is found
Moved the setting of the #result outside the loop. This only needs to be done once you know the answer and not at every iteration.
Use a ternary with a simple boolean instead of strings to know the status of the match and output the final string.
If my assumption is correct that you are really interested in knowing if any item in the array matches, then I suggest using the some method of the array to evaluate it. This is a bit more expressive and removes the need for the looping structure.
let success = false;
const getDataVal = $("#getData").val();
if (getDataVal.length == 20) {
success = res.some(function (val)) {
return val == getDataVal;
});
}
$("#result").html(success ? "Success!" : "No match!");

How to check if a condition in foreach function matched in Javascript?

I have a Javascript function.
I check a condition for every element in an array and if there is a match, I stop the loop.
For example:
var myarray = [5,6,7,8,9,10];
myarray.forEach(function(element){
if(element == 8)
break;
});
//myother functions here..
Everything seems okay so far. But after breaking the loop, my other functions continues to run.
If a match happens in foreach function, i don't want to continue to next functions, if nothing match it can continue.
How can I do this?
For example you could use (version without functions)
var myarray = [5,6,7,8,9,10];
var found = false;
myarray.forEach(function(element){
if(element == 8)
found = true;
});
if (!found) {
//myother functions here..
}
Or if you are just looking for a single element
if (myarray.indexOf(8) == -1) {
//myother functions here..
}

Javascript: action when a string is not found in an array of objects (if statement)

var checkStore=function (book) {
for (var i=0; i<BookStore.length;i++) {
if (book==BookStore[i].title) {
var reply= prompt ('Want to add to your cart?'+ BookStore[i].title);
if (reply==='yes') {
Susan.cart.push(BookStore[i]);
}
}
}
}
How to add to my existing code "if the string is not found, then alert the user 'not found!'". Do I used [else] statement or begin a new one? It's not working correctly when I used else-if statement.
You might want to find the book first, then do your logic:
var checkStore = function(book) {
var found;
for (var i = 0; i < BookStore.length; i++) {
if (book == BookStore[i].title) {
found = BookStore[i];
break;
}
}
if (found) {
var reply = prompt ('Want to add to your cart?' + found.title);
if (reply === 'yes') {
Susan.cart.push(found);
}
} else {
alert('not found!');
}
}
var checkStore=function (book) {
if(BookStore.indexOf(book) < 0){
alert('hello, no book');
} else {
for (var i=0; i<BookStore.length;i++) {
if (book==BookStore[i].title) {
var reply= prompt ('Want to add to your cart?'+ BookStore[i].title);
if (reply==='yes') {
Susan.cart.push(BookStore[i]);
}
}
}
}
}
}
The other answers are totally valid. You can also just make return points which stop the execution of the function at logical endpoints.
var checkStore=function (book) {
for (var i=0; i<BookStore.length;i++) {
if (book==BookStore[i].title) {
var reply= prompt ('Want to add to your cart?'+ BookStore[i].title);
if (reply==='yes') {
Susan.cart.push(BookStore[i]);
return "book added to cart."
}else{
return "book found, but not added to cart."
}
}
}
return "bummer, book not found.";
}
alert(checkStore("book title"));
Fastest solution
This is the shortest way to take your exact existing code and add a few lines and solve this problem: How to add to my existing code "if the string is not found, then alert the user 'not found!'".
var checkStore=function (book) {
var bookWasFound=false; //Line added here
for (var i=0; i<BookStore.length;i++) {
if (book==BookStore[i].title) {
bookWasFound=true; //Line added here
var reply= prompt ('Want to add to your cart?'+ BookStore[i].title);
if (reply==='yes') {
Susan.cart.push(BookStore[i]);
}
}
}
if (!bookWasFound) { //Line added here
alert('Not found!'); //Line added here
} //Line added here
}
Explanation and alternatives
Why don't we use an else statement?
You ask, "Do I used [else] statement[...]?"
You do not. You can not! The reason is because the else part of an if-else statement is executed when the if part is not executed. So if we put that in our loop, every time we compare a book title to the string we're looking for, our else would be executed if the book title didn't match. We only want that to happen once.
It is somewhat difficult to think about this scenario without a concrete example, so I will show what happens if we use an if-else statement.
The code would look like this:
if (book==BookStore[i].title) {
...
} else {
alert('Not found!');
}
Imagine that our BookStore is populated with 3 books: "The C Programming language", "JavaScript: Pocket Reference", and "Everybody Poops".
If the checkStore function is passed in "JavaScript: Pocket Reference". Our loop will go like this:
As soon as we enter the loop, book would be equal to "JavaScript: Pocket Reference", and i = 0 so BookStore[i].title is the same as BookStore[0].title, and the 0th book's title is "The C Programming language".
So the line if(book==BookStore[i].title) { would compare "JavaScript: Poc..." to "The C Prog..." and evaluate to false.
Since the if evaulated to false, the else part gets executed. The else part is alert('Not found!').
Now, we have finished one iteration of our loop, and we compared the string passed in to the first book's title which didn't match, so we gave the alert. But we shouldn't have! If we just kept going, we would see that the second book's title matched, so we shouldn't have told the user that the book wasn't found. It is correct that the book wasn't found, yet, but we should have waited before we announced this to the user.
I may have went into great detail to explain my point, but I believe it is very important. This is one example of when it takes thinking like a programmer or thinking algorithmically to solve the problem.
You have to think about the problem and ask yourself, "How do we know if a book is in the list?". Well, a book is in the list if its title is the same as the title of any book in the list. Because we have to use the word any when we say "...any book in the list", we know that our algorithm must test every book in the list.
We can't tell the user that a book was found, or not found, until we have tested every book in the list, or in our BookStore. We can't tell the user that a book was found, or not found, until our loop has finished.
So what do we do?
You will see this situation over and over again during your programming experience. You need to iterate over a list, and determine if something is in the list.
You can't ever know until you've iterated over every single object in the list, but once you have, how do you know the answer?
The solution is to use what is commonly referred to in programming, a flag. A flag is a variable that has two possible states: true, or false, on or off, yes or no, 1 or 0. It doesn't matter what you call the states. At any time, the flag can only be in one of the two possible states.
We can use a flag by setting it to one state, usually false or 0, then looping through some list and if (...) we set it to true. Each iteration of the loop, if some condition is met, we set our flag to true, and at the end of the loop, we know that the condition was met at some point in the loop, if the flag is true.
The most common way to implement a flag, is to use a boolean variable. That is, a variable which can only be set to true or false. In Javascript, there isn't a boolean variable since any variable can be set to any value. So we just use a regular variable, but still only set it to true or false.
We do that like this:
var myFlag = false;
// OR
var myFlag = true;
So a simple usage of a flag could be to determine if there exists an even number in a given array.
Just like this:
var myArray = [1, 3, 5, 123, 125, 4, 89, 8, 10];
var hasEven = false;
for(var i = 0; i < myArray.length; i++) {
if( myArray[i] % 2 == 0 ) {
hasEven = true;
}
}
if(hasEven) {
alert('Found an even number!');
} else {
alert('Did not find an even number!');
}
Note that you can test the value of a boolean (true or false) variable with if(variableName), you don't have to include the == true like if(variableName == true).
Final implementation
Now we can use our flag to solve our original problem
var checkStore = function(book) {
var bookWasFound = false;
for (var i = 0; i < BookStore.length; i++) {
if (book == BookStore[i].title) {
// If we get in this loop, we must have found a match,
// so we should set our flag to true now
bookWasFound = true
var reply = prompt ('Want to add to your cart? ' + BookStore[i].title);
if (reply === 'yes') {
Susan.cart.push( BookStore[i] );
}
} // End of if statement for prompt
} // End of loop looking for book
if( !bookWasFound ) { // Same as if( bookWasFound == false )
alert('Not found!');
}
} // End of function
Using this flag allows us to keep the inside of the for loop very clean and organized, and handle the results outside of it.

Categories

Resources