I tried using break Statement. but didnt worked out. I wanted to break out from outer loop as soon as some condition matches in inner loop.
angular.forEach(myfilejob, function(fieldMapO) {
var count = 0;
angular.forEach(myfilejob, function(fieldMapI) {
if(fieldMapO.key == fieldMapI.key){
$scope.dupKey = fieldMapI.key;
count ++;
}
});
if(count>1){
$scope.dups = true;
// tried break , but didnt work
}
else{
$scope.dups = false;
}
});
When you use forEach, there is no way to pause iteration - not even by using return. If you want a way to stop iteration in the middle of your loop, you must use an actual for or while loop (probably something like for..in or for..of or a traditional three-statement for(var i = 0; i < whatever; i++ loop if myfilejob is an array).
However, once you have done that, you can then label the loops to get the exact effect you're looking for:
outerDupLoop:
for (var outerIndex in myfilejob) {
var fieldMapO = myfilejob[outerIndex];
var count = 0;
innerDupLoop:
for (var innerIndex in myfilejob) {
var fieldMapI = myfilejob[innerIndex];
if(fieldMapO.key == fieldMapI.key){
$scope.dupKey = fieldMapI.key;
count ++;
}
});
if(count>1){
$scope.dups = true;
break outerDupLoop; // break from the outer loop
} else {
$scope.dups = false;
}
}
(Never mind that the break statement you were trying to add was in the outer loop anyway - removing the labels from this example would make this functionally equivalent. Did you mean to refactor the (count > 1) check so that it would work properly inside the inner loop?)
You can use return, which will essentially break out of the loop. If you want to do it within the inner loop, set a boolean to true, and check for it in the outer loop.
var dupsExist = false;
angular.forEach(myfilejob, function(fieldMapI) {
if(fieldMapO.key == fieldMapI.key){
$scope.dupKey = fieldMapI.key;
dupsExist = true;
return;
}
});
if (dupsExist){
return;
}
I suggest you define a bool when your inner condition is satisfied
angular.forEach(myfilejob, function(fieldMapO) {
var count = 0;
var conditionFlag = false;
angular.forEach(myfilejob, function(fieldMapI) {
if(fieldMapO.key == fieldMapI.key){
$scope.dupKey = fieldMapI.key;
count ++;
//condition is fulfilled so boolean is true now
conditionFlag = true
return false
}
});
if(count>1){
$scope.dups = true;
}
else{
$scope.dups = false;
}
//check if condition is satisfied then exit outer loop too
if(conditionFlag){
return false;
}
});
Hope it helps
Related
There is clearly something wrong with my logic or with the logic of JS (haha).
I really don't understand why one of them works and another one doesn't.
These functions are for checking if every single index in the array is the same. The first one works, and the second one doesn't and I don't see how the logic of these two are different (besides the obvious point of changing the positions).
1.
function isUniform(x) {
var first = x[0];
for(var i = 1; i < x.length; i++) {
if(first === x[i]) {
return true;
i++;
}
} return false;
};
2.
function isUniform(x) {
var first = x[0];
for(var i = 1; i < x.length; i++) {
if(x[i] !== first) {
return false;
i++;
}
} return true;
};
Arrays used :isUniform([1, 1, 1, 2]) and isUniform([1, 1, 1, 1])
Once you return inside a for-loop, the loop stops and the function ends.
In your first example, first will Never be equal to x[i], because you start i at 1 and first === x[0], so the loop will finish and return false.
In your second example, you'll always return false at i = 1, since x[1] !== x[0], so the loop will always return false after the first check.
Here is a breakdown as to how your functions work on a line-by-line level (I've included comments after each statement):
function isUniform(x) {
var first = x[0]; //SET "FIRST" to first element in array
for(var i = 1; i < x.length; i++) { //loop from second element to the end
if(first === x[i]) { //if "FIRST" is equal to this element
return true; //conclude that the ENTIRE ARRAY is uniform and quit function
i++; //incremenet "i" (note, the loop automatically does this, so this will result in an extra increment
}
} return false; //conclude the array is not uniform IF THE FIRST ITEM IS UNIQUE
};
Here is a breakdown of the second function:
function isUniform(x) {
var first = x[0];//SET "FIRST" to first element in array
for(var i = 1; i < x.length; i++) { //loop from second element to the end
if(x[i] !== first) { //if this element is not equal to the first CONCLUDE THAT THE ARRAY IS NOT UNIFORM and quit function
return false;
i++; //again, extra un-needed increment, but it technically does not matter in this case
}
} return true; //CONCLUDE that since no items were NOT equal to the first item, the array is uniform
};
Thus, it should now be clear that the second array fulfills your purpose while the first one does not. Really, the first one checks if any elements other than the first are equal to the first.
I do understand how the following function works in general. BUT why doesn't it exit after the first iteration (when there is a palindrome)? It checks the first character against the last in the if statement, which is true, what should (in my logic) execute the return statement... Thank you for any help explaining this! :)
function palindrome(str) {
var lowerCaseStr = str.toLowerCase();
for (var i = 0; i < lowerCaseStr.length; i++)
debugger;
if (lowerCaseStr[i] === lowerCaseStr[lowerCaseStr.length - i - 1]){
return true;
}
return false;
}
It doesn't exit after the first iteration but after lowerCaseStr.length iterations because your code is equivalent to the code below
function palindrome(str) {
var lowerCaseStr = str.toLowerCase();
for (var i = 0; i < lowerCaseStr.length; i++){
debugger;
}
if (lowerCaseStr[lowerCaseStr.length] === lowerCaseStr[-1]){
return true;
}
return false;
}
that is, it iterates lowerCaseStr.length; times but the only thing it does for each iterates is call debugger after that it tests to elements in the array that doesn't exists. (Both indices are out of bounds). That results in a comparison of two times undefined undefined === undefined which is always true.
As a side node if you return either true or false depending on a boolean expression then consider using one return statement instead:
return (lowerCaseStr[i] === lowerCaseStr[lowerCaseStr.length - i - 1]);
You need to switch the logic, check for inequality and return false. If you reach the end, return true.
function palindrome(str) {
var lowerCaseStr = str.toLowerCase();
for (var i = 0; i < lowerCaseStr.length; i++) {
debugger;
if (lowerCaseStr[i] !== lowerCaseStr[lowerCaseStr.length - i - 1]) {
return false;
}
}
return true;
}
So I'm trying to make a loop that does something and then when it is finished set a var to false then move to the next loop (or otherwise exit and end the loop). Code:
var loop = true;
while (loop = true)
{
console.log("whatevers");
loop = false;
}
while (loop = false)
{
console.log("meh");
//continue endProgram;
}
So what am I doing wrong here?
= is just assignment, where == or === is for comparisons. Assignment of a variable is evaluated as the expression after the assignment (see #Oka comment). For example: (loop = true => true while loop = false => false) Use == or === instead:
var loop = true;
while (loop == true)
{
console.log("whatevers");
loop = false;
}
while (loop == false)
{
console.log("meh");
//continue endProgram;
}
Try this way
-------------------------------------------------------------------
var loop = true;
while (loop)
{
console.log("whatevers");
loop = false;
}
while (!loop)
{
console.log("meh");
//continue endProgram;
}
while(loop) is the same with while(loop == true )..but loop = true means that you set variable loop equal to true.So try this:
var loop = true;
while (loop)
{
console.log("whatevers");
loop = false;
}
while (!loop)
{
console.log("meh");
}
I am trying to using a for loop for trying to validate the input of the user and this is the code i got.
function Valid() {
objfieldid = ["userMail", "userCont"]
objboxid = ["cancelMail", "cancelCont"]
return objfieldid.every(callnonvalid)
}
function callnonvalid(id) {
var valid = false
var objlength = objfieldid.length
objlength--;
for (var i = objlength; i >= 0; i--){
var cobj = document.getElementById(objboxid[i]).checked;
if (document.getElementById(id).value != "" ){
var obj = document.getElementById(id).value;
} else if (cobj == true) {
alert(i); //return 1, 1
return true
} else {
return false
}
}
}
As you can see, in the code, the for loop is running twice. but the i variable is left unchanged. Why would this happen?
btw, I did read different material about closure and i am sure there didnt got a closure problem
EDIT:guys please note that i did noticed the array is zero based, and i did minus the objlength by one.
Mistakes were found after checking the code carefully. The Mistake that I made was that I should not use the return for the out since that would stop the function from working, however that array.every Called the function twice which make the i not decreasing
I'm not sure why you're decrementing in your loop, because the performance gain would be infinitesimally small (it may even be slower, e.g. in Chrome/V8) and working in reverse order can get confusing further down the line, but that's your choice and I don't know enough about what you're doing to judge.
Either way, I don't think you'd want to decrement objlength before the loop begins as you are doing now. The whole point of a loop is to handle the incrementing/decrementing in the condition statement of the loop.
You would only decrement manually like that if you were going to move your if/else if/else statement into a closed over function and execute it recursively, decrementing the objlength from within the closure. Which would work, but it's unnecessarily complicated for what you're doing and you would gain nothing for rewriting the whole thing.
So, sticking with the looping approach, perhaps try either of these:
function Valid() {
objfieldid = ["userMail", "userCont"];
objboxid = ["cancelMail", "cancelCont"];
return objfieldid.every(callnonvalid);
}
function callnonvalid(id) {
var valid = false;
var objlength = objfieldid.length;
for(var i = 0; i < objlength; i++){
var cobj = document.getElementById(objboxid[i]).checked;
if (document.getElementById(id).value != "" ){
var obj = document.getElementById(id).value;
} else if (cobj == true) {
alert(i);
return true;
} else {
return false;
}
}
}
or, if you want to decrement, use while instead of for:
function Valid() {
objfieldid = ["userMail", "userCont"];
objboxid = ["cancelMail", "cancelCont"];
return objfieldid.every(callnonvalid);
}
function callnonvalid(id) {
var valid = false;
var i = objfieldid.length;
while(i--){
var cobj = document.getElementById(objboxid[i]).checked;
if (document.getElementById(id).value != "" ){
var obj = document.getElementById(id).value;
} else if (cobj == true) {
alert(i);
return true;
} else {
return false;
}
}
}
Because the array objboxid[] has only two elements, the first time through your loop objboxid[2] will be attempting to fetch an array index that is out-of-bounds.
You probably meant something like:
for (var i = objlength; i > 0; i--){
var cobj = document.getElementById(objboxid[i-1]).checked;
or perhaps
for (var i = objlength-1; i >= 0; i--){
var cobj = document.getElementById(objboxid[i]).checked;
I am trying to create a page which needs to preform lots of loops. Using a while/for loops cause the page to hang until the loop completes and it is possible in this case that the loop could be running for hours. I have also tried using setTimeout, but that hits a recursion limit. How do I prevent the page from reaching a recursion limit?
var looper = {
characters: 'abcdefghijklmnopqrstuvwxyz',
current: [0],
target: '',
max: 25,
setHash: function(hash) {
this.target = hash;
this.max = this.characters.length;
},
getString: function() {
string = '';
for (letter in this.current) {
string += this.characters[this.current[letter]];
}
return string;
},
hash: function() {
return Sha1.hash(this.getString());
},
increment: function() {
this.current[0] += 1;
if (this.current[0] > this.max) {
if (this.current.length == 1) {
this.current = [0, 0];
} else {
this.current[1] += 1;
this.current[0] = 0;
}
}
if (this.current[1] > this.max) {
if (this.current.length == 2) {
this.current[2] == 0;
} else {
this.current[3] += 1;
this.current[2] = 0;
}
}
},
loop: function() {
if (this.hash() == this.target) {
alert(this.getString());
} else {
this.increment();
setTimeout(this.loop(), 1);
}
}
}
setInterval is the usual way, but you could also try web workers, which would be a more straightforward refactoring of your code than setInterval but would only work on HTML5 browsers.
http://dev.w3.org/html5/workers/
Your setTimeout is not doing what you think it's doing. Here's what it's doing:
It encounters this statement:
setTimeout(this.loop(), 1);
It evaluates the first argument to setTimeout, this.loop(). It calls loop right there; it does not wait for a millisecond as you likely expected.
It calls setTimeout like this:
setTimeout(undefined, 1);
In theory, anyway. In reality, the second step never completes; it recurses indefinitely. What you need to do is pass a reference to the function rather than the returned value of the function:
setTimeout(this.loop, 1);
However, then this will be window on the next loop, not looper. Bind it, instead:
setTimeout(this.loop.bind(this), 1);
setInterval might work. It calls a function every certain amount of milliseconds.
For Example
myInterval = setInterval(myFunction,5000);
That will call your function (myFunction) every 5 seconds.
why not have a loop checker using setInterval?
var loopWorking = false;
function looper(){
loopWorking = true;
//Do stuff
loopWorking = false;
}
function checkLooper()
{
if(loopWorking == false)
looper();
}
setInterval(checkLooper, 100); //every 100ms or lower. Can reduce down to 1ms
If you want to avoid recursion then don't call this.loop() from inside of this.loop(). Instead use window.setInterval() to call the loop repeatedly.
I had to hand-code continuation passing style in google-code prettify.
Basically I turned
for (var i = 0, n = arr.length; i < n; ++i) {
processItem(i);
}
done();
into
var i = 0, n = arr.length;
function work() {
var t0 = +new Date;
while (i < n) {
processItem(i);
++i;
if (new Date - t0 > 100) {
setTimeout(work, 250);
return;
}
}
done();
}
work();
which doesn't hit any recursion limit since there are no recursive function calls.