Reputation: 97
So I have been banging my head over this seemingly insignificant issue. I don't necessarily know what to search for. I have scoured around for solutions. I need to make a copy of 2D array. The array consists of objects (a class I created call Cell), but the as soon as I make a copy I store that copy into a hash map (for possible reference later), then continue to modify the original array. The issue is that the modifications to the original also affect the copy now in the hash map. Essentially at the end of the day, my hash map will consist of many versions of the same grid. I have tried array.clone(), System.arraycopy(...), Arrays.copyof(), the traditional for loop copying scheme.... Finally I realized that I need what was called a deep copy, where you copy each data field of each object into a new object into the array copy....yeah, that didn't work either. Take a look:
static Cell[][] gridCopy;
...
Cell[][] grid = getGrid(file); //get grid from a file (this is Sudoku if you must know)
...
static boolean SolveSudoku(Cell grid[][])
{
// If there is no unassigned location, we are done
if (unassigned == null)
return true; // success!
int row = unassigned.row;
int col = unassigned.col;
ArrayList<Integer> domain = unassigned.domain;
// consider digits 1 to 9
for (int num = 0; num < domain.size(); num++)
{
//if looks promising
if (isSafe(grid, row, col, domain.get(num)))
{
//gridCopy = new Cell[N][N];
instance++;
// make tentative assignment
grid[row][col].value = domain.get(num);
//here is my attempt at a deep copy
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
gridCopy[i][j] = new Cell(grid[i][j].row, grid[i][j].col, grid[i][j].value, grid[i][j].domain);
states.put(instance, gridCopy); //save the current state in a map for reference if we backtrack
//as soon as I change things here in the original, the copy in the 'states' map also changes
updateSpecifiedDomains(grid, row, col, domain.get(num), true);
printGrid(grid, "Instance" + String.valueOf(instance));
// return, if success, yay!
if (SolveSudoku(grid, choice))
return true;
// failure, un-assign & try again
//int temp = grid[row][col].value;
grid = states.get(instance); //retain previous state
grid[row][col].value = UNASSIGNED;
/*updateSpecifiedDomains(grid, row, col, temp, false);
while (domain.contains(temp))
grid[row][col].domain.remove((Integer)temp);*/
//domain.remove((Integer)num);
}
}
count++;
instance--;
return false; // this triggers backtracking
}
Upvotes: 2
Views: 3541
Reputation: 1470
If you are talking just about modifying the original array, then Arrays.copyof(...) should suffice because it creates a new array (not the same indeed), but I'm guessing that when you refer to "modifying the original", you are referring to modifying the objects referenced in it (not the array per se).
So you first need to implement a copy constructor or a copy method for each of the objects and then iterate the array and copy the objects into a new array.
Using Guava, you can easily do it like this (in this example that would be after implementing the clone method):
YourClass [] originalArray = new YourClass[]{...};
YourClass [] arrayCopy = Collections2.transform(Arrays.asList(originalArray), new Function<YourClass, YourClass>() {
@Nullable
@Override
public Object apply(YourClass anObject) {
return anObject.clone();
}
}).toArray();
Or if you don't want the unnecessary overhead of having to convert to a Collection and then back to an array, you can use this small code I implemented (which also use Guava, but just the Function class): Transform a Generic Array Efficiently Using Guava
Finally I must say that you can implement a copy constructor or a copy method (or clone, or whatever you may want to call it) differently depending on your specific needs: Deep copy, shallow copy, clone
Upvotes: 0
Reputation: 599
Everything in java is a pointer. This means that copying an array they way you are implementing it creata indeed a pointer to a new array, but the elements in the arrays point to the elements in the old array, thus making modifying them via methods affect both arrays. In order for that not to happen, you must implement a deep-cloning mechanism to clone the elements of the original array, and insert the newly created clones into the new array. Modifying a clone will not affect the original element, because they point to different addresses in the heap.
Upvotes: 0
Reputation: 13222
You are creating a shallow copy of your objects. Array.clone() will only work on primitive types. You should create a method in the Class of the objects you are trying to copy that creates and returns a new instance of the class with the same attribute values. Then you can loop through your array getting a copy of each object and add them to a new array then store the new array to your hashmap.
Example:
public class MyClass()
{
private String temp;
public MyClass(String temp)
{
this.temp = temp;
}
public MyClass copy()
{
MyClass copy = new MyClass(this.temp);
//set attributes in constructor or using setters so they are the same as this object
return copy;
}
}
Upvotes: 2