Reputation: 798
I have a program that, given an array, returns all possible combinations (permutations?) of its values. I do that recursively. And it calculate all ok, but, what I want to do is, instead of printing the resulting array each iteration, I want to append it to an Array List I declared before.
public static final int NUMBER_OF_CELLS = 3;
public static final int NUMBER_OF_ATTRIBUTES = 3;
// I want all possible combinations all elements 0, 1 and 2, taken 3 at a time
private ArrayList<State> states= new ArrayList<State>();
public void createAllPossibleStates() {
State state = new State(NUMBER_OF_CELLS);
setValues(0, state);
System.out.println(states); // This gives me a wrong ouput and I don't know why
}
public void setValues(int cell, State state) {
if(cell == NUMBER_OF_CELLS) {
// System.out.println(state.toString()); // Instead of this
states.add(state); // I want this. Append the array to an array list
}
}
else {
for(int i = 0; i < NUMBER_OF_ATTRIBUTES; i++) {
state.values[cell] = i;
setValues(cell + 1, state);
}
}
}
But the result of the final Array List contining all possible states is wrong. Instead of this:
[[0, 0, 0],[0, 0, 1],[0, 0, 2],[0, 1, 0],[0, 1, 1],[0, 1, 2],[0, 2, 0],[0, 2, 1],[0, 2, 2],[1, 0, 0],[1, 0, 1],[1, 0, 2],[1, 1, 0],[1, 1, 1],[1, 1, 2],[1, 2, 0],[1, 2, 1],[1, 2, 2],[2, 0, 0],[2, 0, 1],[2, 0, 2],[2, 1, 0],[2, 1, 1],[2, 1, 2],[2, 2, 0],[2, 2, 1],[2, 2, 2]]
I get this:
[[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]]
I can't wonder why this happens. Maybe the recursion fact causes the appending operation work the wrong way?
Upvotes: 0
Views: 88
Reputation: 424983
You only have 1 instance of State
and you're passing it down through the call stack, modifying it, then adding it to the list multiple times (one for each recursion termination). Of course, since there's only one object involved, it will have whatever state (no pun intended) was the last state given to it.
Without modifying too much code, you need to make a copy of the State
object and add the copy to the list - to permanently capture the state at the time you added it to the list.
There are a few standard ways of doing that, but perhaps the easiest to understand and the most commonly used is the copy constructor:
public State(State state) {
this.values = Arrays.copyOf(state.values, state.values.length);
// copy over whatever other fields you need
}
Then in your code:
states.add(new State(state));
Upvotes: 1
Reputation: 33726
Hi,
You're always adding the same State object to the ArrayList. Every recursion loop is modifying the same State object.
You must implement clone in State class:
@Override
protected State clone() throws CloneNotSupportedException {
State state = new State(NUMBER_OF_CELLS);
System.arraycopy(this.values, 0, state.values, 0, this.values.length);
return state;
}
And replace states.add(state);
by states.add(state.clone());
Upvotes: 1