Algorithm for permutation of a configuration setting class

Viewed 73

I've been thinking the solution for my project the whole day that needs to permutate n list of objects according to "step" field inside its class. I have the following class:

public class Configuration{
     private String name;
     private int start; //starting value
     private int end;  //ending value
     private int step; //append this to start value until end value is reached
}

//if I have the following sample:
    List<Configuration> configurations = new ArrayList<>();
    Configuration config1 = new Configuration("congif1", 1,2,1);
    Configuration config2 = new Configuration("config2", 100,200,50);

I need to implement a method:

public Object/void print(List<Configuration> configurations);

Such that the expected output would be (in any order as long as the values are complete)

1,100
2,100
1,150
2,150
1,200
2,200

I need to run through all different configuration scenarios based on user's given configuration setup. If I have 3 objects:

Configuration config1 = new Configuration("congif1", 1,2,1);
Configuration config2 = new Configuration("config2", 100,150,50);
Configuration config3 = new Configuration("config3", 1000,2000,500);

Then the output should be:

1,100,1000
2,100,1000
1,150,1000
2,150,1000
1,100,1500
2,100,1500
1,150,1500
2,150,1500
1,100,2000
2,100,2000
1,150,2000
2,150,2000

I tried the following nested loop but it does not permutate all:

for(Configuration config:configurations){
     for(int i=start; i<end; i+=step){
          //code here
     }
}

I think I need a recursion type for this but I really can't figure out how

2 Answers

First, I should point out that your code is not correct. How are start, end and step defined in your loop? How can you access them?

Next, I would add getters and a method to do a permutation between two configurations to your class Configuration much like:

public class Configuration {

     private String name;
     private int start;
     private int end;
     private int step;
     
     public Configuration(...) { // Some constructor }

     public int getStart() { return start; }

     public int getEnd() { return end; }

     public int getStep() { return step; }

     public void permutateWith(Configuration c) {
          for(int i = start; i <= end; i += step) {
               for(int j = c.getStart(); j <= c.getEnd(); j += c.getStep()) {
                    System.out.println(i + "," + j);
               }
          }
     }

}

With this class in place, we can create two instances:

Configuration config1 = new Configuration("congif1", 1,2,1);
Configuration config2 = new Configuration("config2", 100,200,50);

and ad them to a list:

List<Configuration> configurations = new ArrayList<>();
configurations.add(config1);
configurations.add(config2);

Now, you can write a method printPermutations(List<Configuration> list) such as:

private void printPermutations(List<Configuration> list) {
     
     // Pick one element
     for(int i = 0; i < list.length; i++) {
          // Combine with all the others
          for(int j = i + 1; j < list.length; j++) {
               list.get(i).permutateWith(list.get(j));
          }
     }
}

I haven't tried myself but should solve your problem.

Note: this became longer than I anticipated. If you want the TLDR of the answer, go down to the "3rd block" section.

Hey I think I got it. I used some of your code and with the help of @YodaAndFriends's answer here is my recursive solution.

I will seperate my answer to a few blocks of codes, to describe each one of them more clrealy.

1st block:

import java.util.List;
import java.util.ArrayList;

public class Configuration {

    private String name;
    private int start;
    private int end;
    private int step;
     
    public Configuration(String name, int start, int end, int step) {
        this.name = name;
        this.start = start;
        this.end = end;
        this.step = step;
    }

    public int getStart() {return start;}

    public int getEnd() {return end;}

    public int getStep() {return step;}
    
    public void setStart(int num) {this.start = num;}

Basic class configurations (with obvious List/ArrayList imports). This should be identical to @YodaAndFriends part, I just added a setStart method.

2nd block:

    public static void printStarters(List<Configuration> configurations) {
        System.out.printf("%d",configurations.get(0).getStart());
        for(int i=1; i<configurations.size(); i++) {
            System.out.printf(", %d",configurations.get(i).getStart());
        }
        System.out.println();
    }
    
    public static boolean endPoint(List<Configuration> configurations) {
        for(int i=0; i<configurations.size(); i++) {
            if (configurations.get(i).getStart() != configurations.get(i).getEnd()) {
                return false;
            }
        }
        return true;
    }

Here I wrote some helper methods:

  • printStarters to simply print the current starts of all the configurations within each recursion.
  • endPoint is checking wether we reached the end of the recursion and each of the starts is equal to it's end respectively.

3rd block:

public static void printPermutations(List<Configuration> configurations) {
        int[] starters = new int[configurations.size()];
        for(int i=0; i<configurations.size(); i++) {
            starters[i] = configurations.get(i).getStart();
        }
        printStarters(configurations);
        printPermutations(configurations, starters, 0);
    }
    
    private static void printPermutations(List<Configuration> configurations, int[] starters, int y) {
        if (endPoint(configurations)) {
            return;
        }
        Configuration current = configurations.get(y);
        if (current.getStart() != current.getEnd()) {
            current.setStart(current.getStart() + current.getStep());
            printStarters(configurations);
            printPermutations(configurations, starters, 0);
        }
        else {
            current.setStart(starters[y]);
            printPermutations(configurations, starters, ++y);
        }
    }

This is the actual solution method. printPermutations is overloaded and the first variation is calling the second one.

  • The first printPermutations is setting an int array of starts to reset starts that have reached their respective ends. It then calls the next variation of printPermutations.
  • The second (private) variation is the recursive one, it recieves the array of starts, and an index y in addition to the Configurations list.

How it works: It first check if we reached the endPoint.

If the start of the current configuration (in accordance to index y) is different than it's end, we increase it by step, call printStarters, and recursively call the function back to the first configuration of the list (y = 0).

Else the start is equal to it's end -> we reset it to it's original start value, and call the function on the next configuration of the list.


Hope this wasn't too much explaination, I tried to be as clear as possible. I tested this code together with 3 configs as such:

    public static void main(String[] args) {
        List<Configuration> c = new ArrayList<>();
        Configuration config1 = new Configuration("congif1", 1,2,1);
        Configuration config2 = new Configuration("config2", 100,150,50);
        Configuration config3 = new Configuration("config3", 1000,2000,500);
        c.add(config1);
        c.add(config2);
        c.add(config3);
        printPermutations(c);
    }
}

If you copy all of my code blocks one after the other, it should work perfectly fine. There might be ways to reduce time/memory complexity, but this is what I came up with.

Related