How to break nested loops in JavaScript? [duplicate] - javascript

This question already has answers here:
What's the best way to break from nested loops in JavaScript? [closed]
(18 answers)
Closed 3 years ago.
I tried this:
for(i = 0; i < 5; i++){
for(j = i + 1; j < 5; j++){
break(2);
}
alert(1);
}
only to get:
SyntaxError: missing ; before statement
So, how would I break a nested loop in JavaScript?

You should be able to break to a label, like so:
function foo () {
dance:
for (var k = 0; k < 4; k++) {
for (var m = 0; m < 4; m++) {
if (m == 2) {
break dance;
}
}
}
}

You need to name your outer loop and break that loop, rather than your inner loop - like this.
outer_loop:
for(i=0;i<5;i++) {
for(j=i+1;j<5;j++) {
break outer_loop;
}
alert(1);
}

There are at least five different ways to break out of two or more loops:
1) Set parent(s) loop to the end
for (i = 0; i < 5; i++)
{
for (j = 0; j < 5; j++)
{
if (j === 2)
{
i = 5;
break;
}
}
}
2) Use label
fast:
for (i = 0; i < 5; i++)
{
for (j = 0; j < 5; j++)
{
if (j === 2)
break fast;
}
}
3) Use variable
var exit_loops = false;
for (i = 0; i < 5; i++)
{
for (j = 0; j < 5; j++)
{
if (j === 2)
{
exit_loops = true;
break;
}
}
if (exit_loops)
break;
}
4) Use self executing function
(function()
{
for (i = 0; i < 5; i++)
{
for (j = 0; j < 5; j++)
{
if (j === 2)
return;
}
}
})();
5) Use regular function
function nested_loops()
{
for (i = 0; i < 5; i++)
{
for (j = 0; j < 5; j++)
{
if (j === 2)
return;
}
}
}
nested_loops();

See Aaron's. Otherwise:
j=5;i=5 instead of break.

loop1:
for (var i in set1) {
loop2:
for (var j in set2) {
loop3:
for (var k in set3) {
break loop2; // breaks out of loop3 and loop2
}
}
}
code copied from Best way to break from nested loops in Javascript?
Please search before posting a question. The link was the FIRST related question I saw on the left side of this page!

Unfortunately you'll have to set a flag or use labels (think old school goto statements)
var breakout = false;
for(i=0;i<5;i++)
{
for(j=i+1;j<5;j++)
{
breakout = true;
break;
}
if (breakout) break;
alert(1)
};
The label approach looks like:
end_loops:
for(i=0;i<5;i++)
{
for(j=i+1;j<5;j++)
{
break end_loops;
}
alert(1)
};
edit: label incorrectly placed.
also see:
http://www.devguru.com/Technologies/ecmascript/quickref/break.html
http://www.daaq.net/old/javascript/index.php?page=js+exiting+loops&parent=js+statements

In my opinion, it's important to keep your construct vocabulary to a minimum. If I can do away with breaks and continues easily, I do so.
function foo ()
{
var found = false;
for(var k = 0; (k < 4 && !found); k++){
for(var m = 0; (m < 4 && !found); m++){
if( m === 2){
found = true;
}
}
}
return found;
}
Be warned, after the loop, m and k are one larger that you might think. This is because m++ and k++ are executed before their loop conditions. However, it's still better than 'dirty' breaks.
EDIT: long comment #Dennis...
I wasn't being 100% serious about being 'dirty', but I still think that 'break' contravenes my own conception of clean code. The thought of having multi-level breaks actually makes me feel like taking a shower.
I find justifying what I mean about a feeling about code because I have coded all life. The best why I can think of it is is a combination of manners and grammar. Breaks just aren't polite. Multi level breaks are just plain rude.
When looking at a for statement, a reader knows exactly where to look. Everything you need to know about the rules of engagement are in the contract, in between the parenthesis. As a reader, breaks insult me, it feels like I've been cheated upon.
Clarity is much more respectful than cheating.

Use function for multilevel loops - this is good way:
function find_dup () {
for (;;) {
for(;;) {
if (done) return;
}
}
}

Wrap in a self executing function and return
(function(){
for(i=0;i<5;i++){
for (j=0;j<3;j++){
//console.log(i+' '+j);
if (j == 2) return;
}
}
})()

You return to "break" you nested for loop.
function foo ()
{
//dance:
for(var k = 0; k < 4; k++){
for(var m = 0; m < 4; m++){
if(m == 2){
//break dance;
return;
}
}
}
}
foo();

break doesn't take parameters. There are two workarounds:
Wrap them in a function and call return
Set a flag in the inner loop and break again right after the loop if the flag is set.

Break 1st loop:
for(i=0;i<5;i++)
{
for(j=i+1;j<5;j++)
{
//do something
break;
}
alert(1);
};
Break both loops:
for(i=0;i<5;i++)
{
var breakagain = false;
for(j=i+1;j<5;j++)
{
//do something
breakagain = true;
break;
}
alert(1);
if(breakagain)
break;
};

You can break nested for loops with the word 'break', it works without any labels.
In your case you need to have a condition which is sufficient to break a loop.
Here's an example:
var arr = [[1,3], [5,6], [9,10]];
for (var a = 0; a<arr.length; a++ ){
for (var i=0; i<arr[a].length; i++) {
console.log('I am a nested loop and i = ' + i);
if (i==0) { break; }
}
console.log('first loop continues');
}
It logs the following:
> I am a nested loop and i = 0
> first loop continues
> I am a nested loop and i = 0
> first loop continues
> I am a nested loop and i = 0
> first loop continues
The return; statement does not work in this case.
Working pen

function myFunction(){
for(var i = 0;i < n;i++){
for(var m = 0;m < n;m++){
if(/*break condition*/){
goto out;
}
}
}
out:
//your out of the loop;
}

Related

Is it possible to run a loop in segments? - JavaScript

Since I am still fairly new to js I thought it couldn't hurt to ask more experienced coders about ways to improve my coding habits and to learn efficient basics.
So im wondering if I could run, say 2 lines of code in a loop x amount of times and then x amount of times on the rest of the block.
So instead of this:
for (let i = 0; i <= 10; i++) {
this.shapes[i].x -= 1;
this.shapes[i].draw(this.ctx);
}
for (let i = 0; i <= 10; i++) {
this.shapes[i].x += 1;
this.shapes[i].draw(this.ctx);
}
Does something like this exist?
for (let i = 0; i <= 10; i++) {
//run this section i amount of times
this.shapes[i].x -= 1;
this.shapes[i].draw(this.ctx);
//then run this i amount of times
this.shapes[i].x += 1;
this.shapes[i].draw(this.ctx);
}
The only difference between the two loops' bodies seems to be one statement.
You can use some math to determine the index and some logical statements to determine if that value should be incremented or decremented, here is an example:
for (let i = 0; i <= 21; i++) {
const index = i % 11;
this.shapes[index].x += (i > 10) ? 1 : -1;
this.shapes[index].draw(this.ctx);
}
If it's exactly the same code you can refactor it like this:
for (let delta of [-1, +1]) {
for (let i = 0; i <= 10; i++) {
this.shapes[i].x += delta;
this.shapes[i].draw(this.ctx);
}
}
Another option is to use a function using delta as a parameter
changeShapeByDelta = (delta) => {
for (let i = 0; i <= 10; i++) {
this.shapes[i].x += delta;
this.shapes[i].draw(this.ctx);
}
}
changeShapeByDelta(-1);
changeShapeByDelta(+1);
Another option is to deep copy your initial shapes and restore it after the first draw.
You could ofc. define more variables then i:
for (let i = 0, j=0; i <= 10; i++, j+= 2) {
console.log(i, j);
}
Or use another var in the parent scope:
let j = 0;
for (let i = 0, j=0; i <= 10; i++, j+= 2) {
j += 2
console.log(i, j);
}
Or just use plain old if,else and break statements. Code does not have to look nice all the time.
You can loop 20 times instead of 10 times and then run first code if i<10 else run second. Below is example with simple logging.
for(let i = 0;i<22;i++){
if(i<11) console.log('first')
else console.log('second')
}

How do I minify the following series of for loops into a less compact code?

I have the following code which follows a pattern of loops , I have a feeling that code can be minified to a recursion like code or any less ugly looking code , but I am unable to figure it out.
I want to run six loops one inside the other from 1000 to 10000 in javascript, I look to minify the code if possible.
I am beginner in coding , but all kinds of methods are acceptable for me.
I am updating the code as previous code might get ambigous for some users.
function dummyFunc(x,y){
if( some logic for x == some logic for y){
return true;
}
return false;
}
for(var i = 1000;i < 10000;i++){
for(var j = 1000;j < 10000;j++){
if(dummyFunc(i,j)){
for(var k = 1000;k < 10000;k++){
if(dummyFunc(j,k)){
for(var l = 1000;l < 10000;l++){
if(dummyFunc(k,l)){
for(var m = 1000;m < 10000;m++){
if(dummyFunc(l,m)){
for(var n = 1000;n < 10000;n++){
if(dummyFunc(m,n)){
break;
}
}
}
}
}
}
}
}
}
}
}
You could extract the for loop into a function:
function range(start, end, callback) {
for(let i = start, start < end, i++)
callback(i);
}
That can be used as:
range(1000, 10000, i => {
range(1000, 10000, j => {
range(1000, 10000, k => {
range(1000, 10000, l => {
range(1000, 10000, m => {
range(1000, 10000, n => {
console.log(i, j, k, l, m, n);
});
});
});
});
});
To simplify that even further, you could use a generator that yields an array of values which you can destructured:
function* ranges(start, end, repeats) {
if(repeats > 1) {
for(const values of ranges(start, end, repeats - 1)) {
for(const value of ranges(start, end, 0)) {
yield values.concat(value);
}
}
} else {
for(let i = start; i < end; i++)
yield [i];
}
}
That can be used as:
for(const [i, j, k, l, m, n] of ranges(1000, 10000, 6)) {
console.log(i, j, k, l, m, n);
}
Use the following code. Instead of returning true or false, you should start the loop inside the dummyFunc, this will call the function recursively.
function dummyFunc(x,y){
if( some logic for x == some logic for y)
for(var i = 1000;i < 10000;i++)
for(var j = 1000;j < 10000;j++)
dummyFunc(i,j);
}
for(var i = 1000;i < 10000;i++)
for(var j = 1000;j < 10000;j++)
dummyFunc(i,j);
To add clarity to how recursive function is working (writing in usual recursive function style - return is some condition is satisfied else call function again) you may write it as follows
function dummyFunc(x,y){
if( !(some logic for x == some logic for y))
return;
for(var i = 1000;i < 10000;i++)
for(var j = 1000;j < 10000;j++)
dummyFunc(i,j);
}
for(var i = 1000;i < 10000;i++)
for(var j = 1000;j < 10000;j++)
dummyFunc(i,j);
Here is your complete simplified code
function getDeeper(i, j, start, end, level) {
if(j === end && (i = (i+1)) && (j = start)) {}
if(dummyFunc(i, j)) {
if(level === 4) return;
getDeeper(j, start, start, end, ++level);
}
getDeeper(i, ++j, start, end, level);
}
getDeeper(1000, 1000, 1000, 10000, 0);
Since your question is How do I minify the following series of for loops into a less compact code? and is not specifically asking for a better code example I will instead show you how to fish instead of giving you the fish.
You need to read about Structured program theorem:
It states that a class of control flow graphs (historically called
charts in this context) can compute any computable function if it
combines subprograms in only three specific ways (control structures).
These are
Executing one subprogram, and then another subprogram (sequence)
Executing one of two subprograms according to the value of a boolean expression (selection)
Repeatedly executing a subprogram as long as a boolean expression is true (iteration)
Also worth reading is Flow Diagrams, Turing Machines And Languages With Only Two Formation Rules by Corrado Bohm and Giuseppe Jacopini for whom the theorem is named after.
So if I understand you code correctly then while the example looks like a long task when computed as such
If we assume that your browser makes 1000 * 1000 iterations per
second, this will take 1000 * 1000 * 1000 * 1000 seconds to complete.
That is very long (317 centuries)
as noted by Jonas Wilms,
from my extensive experience with predicates which is that a predicate will only return true or false and if you know that once it is true you can stop processing because you have the result. On the other hand if the result is false then you need to process all of the results. The real trick is not to brute force through all of the values but to quickly eliminate combinations of inputs that don't help lead to a solution.
While I don't know exactly what you are trying to do, I would also take a look at Binary decision diagram and/or Constraint satisfaction which are great ways to simplify complex problems.
Based on the code you provided, you could simplify with the following:
function dummyFunc(x,y){
if( some logic for x == some logic for y){
return true;
}
return false;
}
for(var i = 1000;i < 10000;i++) {
for(var j = 1000;j < 10000;j++) {
if(dummyFunc(i,j)) {
break;
}
}
}
You could argue I am taking your example too literally, but hopefully it either answers your question or illustrates why you need a better example to get a better answer.
the same for loop repeated each time
so you can move it inside the function
function dummyFunc(x) {
for (y = 1000; y < 10000; y++) {
if (some logic for x == some logic for y) {
return y;
}
}
return false;
}
for (var i = 1000; i < 10000; i++) {
if (j = dummyFunc(i)) {
if (k = dummyFunc(j)) {
if (l = dummyFunc(k)) {
if (m = dummyFunc(l)) {
if (n = dummyFunc(m)) {
break;
}
}
}
}
}
}
this solution if you need i,j,k,l,m and n variables
if you don't need those variables
by using recursive function
this solution gives the equal to n variable in your question
function dummyFunc(x) {
numberOfLoops = 6;
for (y = 1000; y < 10000; y++) {
if (some logic forr x == some logic forr y) {
if (numberOfLoops == 0) {
return n;
}
n=dummyFunc(x)
numberOfLoops--;
}
}
return false;
}
for (var i = 1000; i < 10000; i++) {
n = dummyFunc(i)
}
I haven't check my code , your comments would be helpful
I'm still not sure why exactly you would want to do this, but below are two potential solutions depending on the behavior you want at the "break". Neither is very pretty, but they both work for the problem described.
Solution (A) - breaks only the inner-most loop, which would exactly match the behavior described in the question.
function loopenstein(minn, maxx, maxDepth, dummyCall) {
function recursiveLoop(i, minn, maxx, depth, dummyCall) {
for (var j = minn; j < maxx; j++)
if (dummyFunc(i, j)) {
if (depth <= 0) {
console.log("break me daddy...")
return;
}
recursiveLoop(j, minn, maxx, depth - 1, dummyCall))
}
}
for (var i = minn; i < maxx; i++) {
recursiveLoop(i, minn, maxx, maxDepth, dummyCall))
}
}
/* usage */
loopenstein(1000, 10000, 6, dummyFunc)
Solution (B) - breaks completely out of all loops once dummyFunc returns true for the 6th loop.
function loopenstein(minn, maxx, maxDepth, dummyCall) {
//recursive helper function
function loopensteinHelper(i, minn, maxx, depth, dummyCall) {
for (var j = minn; j < maxx; j++)
if (dummyFunc(i, j)) {
if (depth <= 0) {
console.log("break me daddy...")
return true;
} else if (loopensteinHelper(j, minn, maxx, depth - 1, dummyCall)) {
return true;
}
return false;
}
for (var i = minn; i < maxx; i++) {
if (loopensteinHelper(i, minn, maxx, maxDepth, dummyCall)) {
return true;
}
}
return false;
}
/* usage */
var isFound = loopenstein(1000, 10000, 6, dummyFunc)
I would recommend to use promise. Below is the modified version of the code:
var looper = function(start = 1000, end = 10000) {
return new Promise(function(resolve, reject) {
console.log('Starting');
for (; start <= end; start++) {
// Your computation goes here
}
resolve();
});
}
Now if you want to run a loop 3 times use it like:
looper().then(looper()).then(looper())
If you need to run loop 4 times use as:
looper().then(looper()).then(looper()).then(looper())
You can learn more about Promises here

for loop is not stopping why? even I specifically say to stop on 10 in condition

for(var i = 0; i <= 10; i+1){
console.log(i); // the loop goes on and on
}
why this for loop don't stop ? I did specifically typed in condition that it need to stop on 10.
The i+1 is your issue. It should be i = i + 1, i++ or i+=1
These are just different ways of adding 1 to the current value of i
for(var i = 0; i <= 10; i++){
console.log(i);
}
You never change i.
for (var i = 0; i <= 10; i + 1) {
^^^^^
You need to increment i
for (var i = 0; i <= 10; i++) { // or
for (var i = 0; i <= 10; i = i + 1) {
It's missing the =: i is not being mutated:
for(var i = 0; i <= 10; i += 1){
console.log(i); // the loop goes on and on
}
Change it to i++ and it will work. Right now you are just checking against 0+1 every loop iteration, and that will never be > 10.

Happy numbers - recursion

I have an issue with a recursive algorithm, that solves the problem of finding the happy numbers.
Here is the code:
function TestingFunction(number){
sumNumberContainer = new Array(0);
CheckIfNumberIsHappy(number);
}
function CheckIfNumberIsHappy(number){
var sumOfTheNumbers = 0;
for (var i = 0; i < number.length; i++) {
sumOfTheNumbers += Math.pow(parseInt(number[i]), 2);
}
console.log(sumOfTheNumbers);
if(sumOfTheNumbers == 1){
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
//return true;
} else {
sumNumberContainer.push(sumOfTheNumbers);
if(sumNumberContainer.length > 1){
for (var i = 0; i < sumNumberContainer.length - 1; i++) {
for (var j = i + 1; j < sumNumberContainer.length; j++) {
if(sumNumberContainer[i] == sumNumberContainer[j]){
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
//return false;
}
}
}
}
CheckIfNumberIsHappy(sumOfTheNumbers.toString());
}
}
Algorithm is working ALMOST fine. I've tested it out by calling function with different numbers, and console was displaying correct results. The problem is that I almost can't get any value from the function. There are only few cases in which I can get any value: If the number is build out of ,,0", and ,,1", for example 1000.
Because of that, I figured out, that I have problem with returning any value when the function is calling itself again.
Now I ended up with 2 results:
Returning the
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
which is giving an infinity looped number. For example when the number is happy, the function is printing in the console number one again and again...
Returning the
//return true
or
//return false
which gives me an undefined value
I'm a little bit in check by this problem, and I'm begging you guys for help.
I would take a step back and reexamine your problem with recursion in mind. The first thing you should think about with recursion is your edge cases — when can you just return a value without recursing. For happy numbers, that's the easy case where the sum of squares === 1 and the harder case where there's a cycle. So test for those and return appropriately. Only after that do you need to recurse. It can then be pretty simple:
function sumSq(num) {
/* simple helper for sums of squares */
return num.toString().split('').reduce((a, c) => c * c + a, 0)
}
function isHappy(n, seen = []) {
/* seen array keeps track of previous values so we can detect cycle */
let ss = sumSq(n)
// two edge cases -- just return
if (ss === 1) return true
if (seen.includes(ss)) return false
// not an edge case, save the value to seen, and recurse.
seen.push(ss)
return isHappy(ss, seen)
}
console.log(isHappy(23))
console.log(isHappy(22))
console.log(isHappy(7839))
Here's a simplified approach to the problem
const digits = x =>
x < 10
? [ x ]
: [ ...digits (x / 10 >> 0), x % 10 ]
const sumSquares = xs =>
xs.reduce ((acc, x) => acc + x * x, 0)
const isHappy = (x, seen = new Set) =>
x === 1
? true
: seen.has (x)
? false
: isHappy ( sumSquares (digits (x))
, seen.add (x)
)
for (let n = 1; n < 100; n = n + 1)
if (isHappy (n))
console.log ("happy", n)
// happy 1
// happy 7
// happy 10
// ...
// happy 97
The program above could be improved by using a technique called memoization
Your code is almost correct. You just forgot to return the result of the recursive call:
function TestingFunction(number){
sumNumberContainer = new Array(0);
if (CheckIfNumberIsHappy(number))
console.log(number);
}
function CheckIfNumberIsHappy(number){
var sumOfTheNumbers = 0;
for (var i = 0; i < number.length; i++) {
sumOfTheNumbers += Math.pow(parseInt(number[i]), 2);
}
if(sumOfTheNumbers == 1){
return true;
} else {
sumNumberContainer.push(sumOfTheNumbers);
if(sumNumberContainer.length > 1){
for (var i = 0; i < sumNumberContainer.length - 1; i++) {
for (var j = i + 1; j < sumNumberContainer.length; j++) {
if(sumNumberContainer[i] == sumNumberContainer[j]){
return false;
}
}
}
}
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
}
}
for (let i=0; i<100; ++i)
TestingFunction(i.toString()); // 1 7 10 13 ... 91 94 97
I've got the solution, which was given to me in the comments, by the user: Mark_M.
I just had to use my previous
return true / return false
also I had to return the recursive statement in the function, and return the value of the CheckIfTheNumberIsHappy function, which was called in TestingFunction.
The working code:
function TestingFunction(number){
sumNumberContainer = new Array(0);
return CheckIfNumberIsHappy(number);
}
function CheckIfNumberIsHappy(number){
var sumOfTheNumbers = 0;
for (var i = 0; i < number.length; i++) {
sumOfTheNumbers += Math.pow(parseInt(number[i]), 2);
}
console.log(sumOfTheNumbers);
if(sumOfTheNumbers == 1){
return true;
} else {
sumNumberContainer.push(sumOfTheNumbers);
if(sumNumberContainer.length > 1){
for (var i = 0; i < sumNumberContainer.length - 1; i++) {
for (var j = i + 1; j < sumNumberContainer.length; j++) {
if(sumNumberContainer[i] == sumNumberContainer[j]){
return false;
}
}
}
}
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
}
}
Thanks for the great support :)

How to modify this function to return string instead of int

please take a quick look at this function that I have found on the web.
function longestCommonSubstring(string1, string2){
// init max value
var longestCommonSubstring = 0;
// init 2D array with 0
var table = Array(string1.length);
for(a = 0; a <= string1.length; a++){
table[a] = Array(string2.length);
for(b = 0; b <= string2.length; b++){
table[a][b] = 0;
}
}
// fill table
for(var i = 0; i < string1.length; i++){
for(var j = 0; j < string2.length; j++){
if(string1[i]==string2[j]){
if(table[i][j] == 0){
table[i+1][j+1] = 1;
} else {
table[i+1][j+1] = table[i][j] + 1;
}
if(table[i+1][j+1] > longestCommonSubstring){
longestCommonSubstring = table[i+1][j+1];
}
} else {
table[i+1][j+1] = 0;
}
}
}
return longestCommonSubstring;
}
It returns the length of the longest common substring as an int. Now to my question, is it possible to modify this function, so that it returns the actual string instead of just returning the length of the substring, I'm quite new at programming and thought that just modifying this secetion would help if(string1[i]==string2[j]){ push(string1[i]}, but it isn't that easy, because I don't want every single character that is the same in those 2 strings to be added in that array, only those that are exactly the same.
Thanks in advance =)
Well for minimal changes to the existing function you could declare a new variable:
var theCommonString = '';
Then in the middle of the function add a line after this existing one:
longestCommonSubstring = table[i+1][j+1];
that says something like:
theCommonString = string1.substr(i + 1 - longestCommonSubstring,
longestCommonSubstring);
(That i + 1 index may be a little off, I haven't bothered working it out carefully.)
Then at the end just return your new variable instead of the existing one.
Note that if there is more than one common sub string of the same length this will return the last one.
You can just store the whole common substring in the table instead of its length:
function longestCommonSubstring(string1, string2){
// init max value
var longestCommonSubstring = "";
// init 2D array with 0
var table = Array(string1.length);
for(a = 0; a <= string1.length; a++){
table[a] = Array(string2.length);
for(b = 0; b <= string2.length; b++){
table[a][b] = 0;
}
}
// fill table
for(var i = 0; i < string1.length; i++){
for(var j = 0; j < string2.length; j++){
if(string1[i]==string2[j]){
if(table[i][j] == 0){
table[i+1][j+1] = string1[i];
} else {
table[i+1][j+1] = table[i][j] + string1[i];
}
if(table[i+1][j+1].length > longestCommonSubstring.length){
longestCommonSubstring = table[i+1][j+1];
}
} else {
table[i+1][j+1] = 0;
}
}
}
return longestCommonSubstring;
}

Categories

Resources