How to generate all combinations of integers of any size dynamically

510 views Asked by At

I have this function:

public void func1(int d, double delta, double min, double max ) 
{
    if( d == 1 )
    {
        for( double i=min ; i <= max ; i++ )
            System.out.println(i);

    }

    if(d == 2 )
    {
        for( double i=min ; i <= max ; i++ )
            for( int j = min ; j <= max ; j++ )
                System.out.println(i, j);

    }

    if(d == 3 )
    {
        for( double i=min ; i <= max ; i++ )
            for( int j = min ; j <= max ; j++ )
                for( int k=min ; k <= max ; k++ )
                    System.out.println(i, j, k );

    }
}

How to make it dynamic? I.e.,: how to not use the if statement so that the function can work with any given d?
Currently, if I want the function to work with d=5, then I have to write five nested for loops and add an if statement.

2

There are 2 answers

0
Code Different On

Feels like a homework question but I'll bite.

My answer works like an odometer on a car. You have wheels of digits. When each wheel gets to 9, the next one gets bumped up a slot and the current one return to 0. It uses no recursion and maintain the full array of numbers at all time. Instead of println, you can add the array to a list of array to capture all permutations. (The last time I touched Java was in 2004 so pardon me if this doesn't look "modern")

import java.util.Arrays;

public class Main {

    public static void func1(int d, double delta, double min, double max ) {
        double[] arr = new double[d];
        int i,j;

        for (i = 0; i < d; i++) {
            arr[i] = min;
        }

        System.out.println(Arrays.toString(arr));
        while (true) {
            // increase the first slot
            while (arr[0] < max) {
                arr[0] += delta;
                System.out.println(Arrays.toString(arr));
            }

            // find the next slot to increase
            i = 1;
            while (i < d && arr[i] == max) {
                i++;
            }

            // test of all slots contain the max value
            Boolean allMax = true;
            for (j = 0; j < d; j++) {
                if (arr[j] != max) {
                    allMax = false;
                    break;
                }
            }

            if (allMax) {
                // if it does, quit the outer while loop
                break;
            } else if (i < d) {
                // if not, increase that next slot
                arr[i] += delta;
            }

            // reset all slots before it
            for (j = 0; j < i; j++) {
                arr[j] = min;
            }

            System.out.println(Arrays.toString(arr));
        }
    }


     public static void main(String []args) {
        func1(3, 1, 1, 3); // gives 3^3 = 27 permutations
     }
}

There are a couple assumptions that I've made:

  • min < max
  • delta steps perfectly from min to max. For example, delta = 1, min = 1, max = 10. I haven't tested cases like delta = 2, min = 1, max = 2.
4
chiwangc On

You can use the idea of Recursion to tackle this problem. The key idea is that if you want to have d loops, you can simply have a single for-loop, and within that for-loop you will have a function that loops d - 1 times:

loop(int d) {
    for (i = min : max) {
        loop(d - 1)
    }
}

You may refer to the following sample code for reference:

public class Main {

    public static void main(String[] args) {
        func1(3, 1.0, 3.0);
    }

    private static void func1(int d, double min, double max) {
        func1(d, min, max, "");
    }

    private static void func1(int d, double min, double max, String prefix) {
        if (d == 0) {
            System.out.println(prefix);
        } else {
            for (double i = min; i <= max; i++) {
                if (d == 1) {
                    func1(d - 1, min, max, prefix + i);
                } else {
                    func1(d - 1, min, max, prefix + i + ", ");
                }
            }
        }
    }
}

Update

I have modified the code in order to return an array of the double values instead of a string:

public class Main {

    private static List<double[]> combination = new LinkedList<>();
    private static double[] tmpArray;

    public static void main(String[] args) {
        func1(3, 1.0, 3.0);

        for (double[] result : combination) {
            for (int i = 0; i < result.length; i++) {
                if (i != result.length - 1) {
                    System.out.print(result[i] + ", ");
                } else {
                    System.out.print(result[i]);
                }
            }
            System.out.println();
        }
    }

    private static void func1(int d, double min, double max) {
        tmpArray = new double[d];
        func2(d, min, max);
    }

    private static void func2(int d, double min, double max) {
        if (d == 0) {
            //System.out.println(prefix);
            double[] newArray = new double[tmpArray.length];
            System.arraycopy(tmpArray, 0, newArray, 0, tmpArray.length);
            combination.add(newArray);
        } else {
            for (double i = min; i <= max; i++) {
                tmpArray[d - 1] = i;
                func2(d - 1, min, max);
            }
        }
    }
}