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

Viewed 377

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;
                     }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
8 Answers

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

  1. Executing one subprogram, and then another subprogram (sequence)
  2. Executing one of two subprograms according to the value of a boolean expression (selection)
  3. 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

Related