Как мне скопировать 2-мерный массив в Java?
Мне нужно сделать копию довольно большого двухмерного массива для проекта, над которым я работаю. У меня есть два 2D-массива:
int[][]current;
int[][]old;
У меня также есть два способа сделать копирование. Мне нужно скопировать массив, потому что текущий регулярно обновляется.
public void old(){
old=current
}
а также
public void keepold(){
current=old
}
Однако это не работает. Если бы я должен был назвать старый, обновить текущее, а затем вызвать keepold, текущий не равен тому, что было изначально. С чего бы это?
Спасибо
11 ответов
current=old
или же old=current
заставляет два массива ссылаться на одну и ту же вещь, поэтому, если вы впоследствии измените current
, old
будет изменен тоже. Чтобы скопировать содержимое массива в другой массив, используйте цикл for
for(int i=0; i<old.length; i++)
for(int j=0; j<old[i].length; j++)
old[i][j]=current[i][j];
PS: для одномерного массива вы можете избежать создания собственного цикла for, используя Arrays.copyOf
Начиная с Java 8, используя API потоков:
int[][] copy = Arrays.stream(matrix).map(r -> r.clone()).toArray(int[][]::new);
r
относится к row
в 2D матрице.
/** * Clones the provided array * * @param src * @return a new clone of the provided array */ public static int[][] cloneArray(int[][] src) { int length = src.length; int[][] target = new int[length][src[0].length]; for (int i = 0; i < length; i++) { System.arraycopy(src[i], 0, target[i], 0, src[i].length); } return target; }
Можно ли изменить этот код для поддержки n-мерных массивов объектов?
Вам нужно будет поддерживать произвольную длину массивов и проверять, имеют ли src и destination одинаковые размеры, и вам также нужно будет рекурсивно копировать каждый элемент каждого массива, если объект также был массивом.
Прошло много времени с тех пор, как я опубликовал это, но я нашел хороший пример одного способа создания класса n-мерного массива. Класс принимает ноль или более целых чисел в конструкторе, определяя соответствующий размер каждого измерения. Класс использует базовый плоский массив Object[]
и вычисляет индекс каждого элемента, используя размеры и массив множителей. (Вот как создаются массивы на языке программирования C.)
Копирование экземпляра NDimensionalArray
было бы так же просто, как копировать любой другой 2D-массив, хотя вы должны утверждать, что каждый NDimensionalArray
Объект имеет равные размеры. Это, вероятно, самый простой способ сделать это, так как нет рекурсии, и это делает представление и доступ намного проще.
Я решил это, написав простую функцию для копирования многомерных массивов int с помощью System.arraycopy
public static void arrayCopy(int[][] aSource, int[][] aDestination) {
for (int i = 0; i < aSource.length; i++) {
System.arraycopy(aSource[i], 0, aDestination[i], 0, aSource[i].length);
}
}
или на самом деле я улучшил его для моего случая использования:
/**
* Clones the provided array
*
* @param src
* @return a new clone of the provided array
*/
public static int[][] cloneArray(int[][] src) {
int length = src.length;
int[][] target = new int[length][src[0].length];
for (int i = 0; i < length; i++) {
System.arraycopy(src[i], 0, target[i], 0, src[i].length);
}
return target;
}
Вы также можете сделать следующее:
public static int[][] copy(int[][] src) {
int[][] dst = new int[src.length][];
for (int i = 0; i < src.length; i++) {
dst[i] = Arrays.copyOf(src[i], src[i].length);
}
return dst;
}
Используя java 8, это можно сделать с помощью
`int[][] destination=Arrays.stream(source)
.map(a -> Arrays.copyOf(a, a.length))
.toArray(int[][]::new);
Массивы в java являются объектами, и все объекты передаются по ссылке. Чтобы действительно "скопировать" массив, вместо создания другого имени для массива, вам нужно пойти и создать новый массив и скопировать все значения. Обратите внимание, что System.arrayCopy будет полностью копировать одномерные массивы, но НЕ двухмерные. Причина в том, что двумерный массив на самом деле является одномерным массивом одномерных массивов, а arrayCopy копирует указатели на те же внутренние одномерные массивы.
Вот как вы можете сделать это с помощью циклов.
public static int[][] makeCopy(int[][] array){
b=new int[array.length][];
for(int row=0; row<array.length; ++row){
b[row]=new int[array[row].length];
for(int col=0; col<b[row].length; ++col){
b[row][col]=array[row][col];
}
}
return b;
}
Вы также можете использовать для каждого цикла
int r=0;
for(int[] array:old){
int c=0;
for(int element:array)
current[r][c++]=array;
r++;
}
Или
int c=0;
for(int array[]:old){
System.arraycopy(array,0,current[c++],0,array.length);
}
Однако что-то вроде:
int c=0;
for(int[] array:old){
current[c++]=array;
}
было бы неправильно, поскольку он просто копировал бы ссылки на старые подмассивы, а изменения, сделанные в старых, отражались бы в текущих.
Я использую эту функцию:
public static int[][] copy(final int[][] array) {
if (array != null) {
final int[][] copy = new int[array.length][];
for (int i = 0; i < array.length; i++) {
final int[] row = array[i];
copy[i] = new int[row.length];
System.arraycopy(row, 0, copy[i], 0, row.length);
}
return copy;
}
return null;
}
Большим преимуществом этого подхода является то, что он также может копировать массивы, которые не имеют одинаковое количество строк, например:
final int[][] array = new int[][] { { 5, 3, 6 }, { 1 } };
current = old ;
Операции присваивания не копируют элементы одного массива в другой. Вы просто делаете current
матрица относится к old
матрица. Вы должны сделать член мудрую копию.
public static byte[][] arrayCopy(byte[][] arr){
if(arr!=null){
int[][] arrCopy = new int[arr.length][] ;
System.arraycopy(arr, 0, arrCopy, 0, arr.length);
return arrCopy;
}else { return new int[][]{};}
}
Вы можете попробовать код ниже,
public void multiArrayCopy(int[][] source,int[][] destination){
destination=source.clone();}
Надеюсь, что это работает.