Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to convert nested loop to recursive function

I'm trying to create a recursive version of the following nested loops and to get the same results as the reference code. The example is below.

This is a version on Codepen http://codepen.io/anon/pen/XbQMLv

(The intent of the code is to output only unique combinations of integers from the indexes.)

Original code and output:

var len = 4;

for (var a = 0; a < len; a++) {
  for (var b = a + 1; b < len; b++) {
    for (var c = b + 1; c < len; c++) {
      console.log(a, b, c);
    }
  }
}
// Outputs:
// 0 1 2
// 0 1 3
// 0 2 3
// 1 2 3

Recursive code and output:

var len = 4;
var end = 3;
var data = [];

var loop = function (index) {
  if (index === end) {
    console.log(data);
    return;
  }
  for (var i = index; i < len; i++) {
    data[index] = i;
    loop(i + 1);
  }
}

loop(0);
// Outputs:
// [ 0, 1, 2 ]
// [ 0, 2, 3 ]
// [ 1, 3, 2 ]
// [ 2, 3, 3 ]

Not sure what I'm missing here.

like image 300
Geuis Avatar asked Aug 13 '15 04:08

Geuis


People also ask

Can we replace loop with recursion?

The solution is to replace the iteration with recursion. Unlike most procedural looping constructs, a recursive function call can be given a meaningful name -- this name should reflect the loop invariant. (In the example, the loop invariant is that the gcd of a and b is unchanged on each iteration).

Is a nested for loop recursive?

Yes. This can be performed by recursive programming.

Are nested loops better than recursion?

Recursion can be seen as "just" another way of doing loops. The main advantage is code readability, as you can see in this Stackoverflow question, in this case when there are a lot of nested loops. For an overview of other cases of recursion vs loops, check out this pdf.


2 Answers

You have a single little error in your code:

You call a recursive function from your i + 1, but not your index + 1.
It causes index to be equal not current array index but it's value.

For example, when you passed [0, 1, 2], your data now is [0, 1] and you are about to insert 3, you call loop(3 + 1), index 4 goes out of an array range. if (index === end) condition fails and it doesn't output. for (var i = index; i < len; i++) loop fails as well, and everything is going wrong.

It should be:

var len = 4;
var end = 3;
var data = [];

var loop = function (index) {
  if (index === end) {
    console.log(data);
    return;
  }
  for (var i = index; i < len; i++) {
    data[index] = i;
    loop(index + 1); // <--- HERE
  }
}

loop(0);

Here is the working JSFiddle demo.

Update:

Oh, now I see. You need a[i] > a[i-1] condition to be true for all combinations. Just add a start variable which will save the last inserted value in order to comply with this rule.

var len = 4;
var end = 3;
var data = [];

var loop = function (start, index) {
  if (index === end) {
    document.body.innerHTML += "<br/>" + data;
    return;
  }
  for (var i = start; i < len; i++) { // We start from 'start' (the last value + 1)
    data[index] = i;
    loop(i + 1, index + 1); // Here, we pass the last inserted value + 1
  }
}

loop(0, 0); // At beginning, we start from 0

Updated JSFiddle demo with passing argument.

You can check the previous value instead of passing a value as an argument if it looks wrong for you. Condition will be like "if it is a first number, start from 0; else - start from the next number after the previous one".

var start = (index === 0 ? 0 : data[index-1] + 1);  

Updated JSFiddle demo with calculating start.

like image 183
Yeldar Kurmangaliyev Avatar answered Sep 27 '22 17:09

Yeldar Kurmangaliyev


As you are having three for loops one inside another, you have to pass 2 arguments for recursion function.

var len = 4;
var end = 3;
var data = [];

var loop = function(start, index) {
  if (index === end) {
    console.log(data);
    return;
  }
  for (var i = start; i < len; i++) {
    data[index] = i;
    loop(i + 1, index + 1); //Pass as like a+1 & b+1
  }
}

loop(0, 0);
like image 41
Laxmikant Dange Avatar answered Sep 27 '22 17:09

Laxmikant Dange