Comment puis-je faire une copie profonde d'un tableau 2d en Java?

Je viens de me faire mordre en utilisant .clone() sur mon tableau 2d boolean, pensant que c'était une copie profonde.

Comment puis-je effectuer une copie de mon boolean[][] tableau?

Devrais-je le parcourir et faire une série de System.arraycopy?

39
demandé sur Radiodef 2009-10-14 11:46:08

6 réponses

Oui, vous devez itérer sur un tableau booléen 2D afin de le copier en profondeur. Regardez aussi les méthodes java.util.Arrays#copyOf si vous êtes sur Java 6.

Je suggère le code suivant pour Java 6:

public static boolean[][] deepCopy(boolean[][] original) {
    if (original == null) {
        return null;
    }

    final boolean[][] result = new boolean[original.length][];
    for (int i = 0; i < original.length; i++) {
        result[i] = Arrays.copyOf(original[i], original[i].length);
        // For Java versions prior to Java 6 use the next:
        // System.arraycopy(original[i], 0, result[i], 0, original[i].length);
    }
    return result;
}
49
répondu Rorick 2009-10-14 07:58:41

Je suis fan de L'utilitaire Arrays. Il a une méthode copyOf qui fera une copie profonde d'un tableau 1-D pour vous, donc vous voudriez quelque chose comme ceci:

//say you have boolean[][] foo;
boolean[][] nv = new boolean[foo.length][foo[0].length];
for (int i = 0; i < nv.length; i++)
     nv[i] = Arrays.copyOf(foo[i], foo[i].length);
8
répondu perimosocordiae 2009-10-14 07:52:58

J'ai réussi à trouver une copie profonde de tableau récursif. Il semble fonctionner assez bien même pour les tableaux multidimensionnels avec des longueurs de dimension variables, par exemple

private static final int[][][] INT_3D_ARRAY = {
        {
                {1}
        },
        {
                {2, 3},
                {4, 5}
        },
        {
                {6, 7, 8},
                {9, 10, 11},
                {12, 13, 14}
        }
};

Voici la méthode utilitaire.

@SuppressWarnings("unchecked")
public static <T> T[] deepCopyOf(T[] array) {

    if (0 >= array.length) return array;

    return (T[]) deepCopyOf(
            array, 
            Array.newInstance(array[0].getClass(), array.length), 
            0);
}

private static Object deepCopyOf(Object array, Object copiedArray, int index) {

    if (index >= Array.getLength(array)) return copiedArray;

    Object element = Array.get(array, index);

    if (element.getClass().isArray()) {

        Array.set(copiedArray, index, deepCopyOf(
                element,
                Array.newInstance(
                        element.getClass().getComponentType(),
                        Array.getLength(element)),
                0));

    } else {

        Array.set(copiedArray, index, element);
    }

    return deepCopyOf(array, copiedArray, ++index);
}

EDIT: a mis à jour le code pour fonctionner avec des tableaux primitifs.

8
répondu Karl Bennett 2013-04-28 17:14:07

Oui, c'est la seule façon de le faire. Aucun {[0] } pas commons-lang n'offre de copie profonde pour les tableaux.

6
répondu Aaron Digulla 2009-10-14 07:51:34

En Java 8, cela peut être accompli comme un one-liner en utilisant lambdas:

<T> T[][] deepCopy(T[][] matrix) {
    return java.util.Arrays.stream(matrix).map(el -> el.clone()).toArray($ -> matrix.clone());
}
6
répondu SlavaSt 2015-07-26 12:49:26

Voici un exemple réfléchissant utilisant java.lang.reflect.Array ce qui est plus robuste et un peu plus facile à suivre. Cette méthode va copier n'importe quel tableau, et copie profondément les tableaux multidimensionnels.

package mcve.util;

import java.lang.reflect.*;

public final class Tools {
    private Tools() {}
    /**
     * Returns a copy of the specified array object, deeply copying
     * multidimensional arrays. If the specified object is null, the
     * return value is null. Note: if the array object has an element
     * type which is a reference type that is not an array type, the
     * elements themselves are not deep copied. This method only copies
     * array objects.
     *
     * @param  array the array object to deep copy
     * @param  <T>   the type of the array to deep copy
     * @return a copy of the specified array object, deeply copying
     *         multidimensional arrays, or null if the object is null
     * @throws IllegalArgumentException if the specified object is not
     *                                  an array
     */
    public static <T> T deepArrayCopy(T array) {
        if (array == null)
            return null;

        Class<?> arrayType = array.getClass();
        if (!arrayType.isArray())
            throw new IllegalArgumentException(arrayType.toString());

        int length = Array.getLength(array);
        Class<?> componentType = arrayType.getComponentType();

        @SuppressWarnings("unchecked")
        T copy = (T) Array.newInstance(componentType, length);

        if (componentType.isArray()) {
            for (int i = 0; i < length; ++i)
                Array.set(copy, i, deepArrayCopy(Array.get(array, i)));
        } else {
            System.arraycopy(array, 0, copy, 0, length);
        }

        return copy;
    }
}
0
répondu Radiodef 2018-07-29 22:56:53