I have two identical ArrayLists, say l1
and l2
. Both are multi-dimensional, for instance ArrayList<ArrayList<Boolean>>
.
When I create and populate l1
, I use new ArrayList<>(l1);
to initialise l2
. If these were Arrays of a single dimension, me editing l2
would leave l1
unchanged, but since they are not, adding new Booleans to l2
also changes l1
. If I were to add a new ArrayList to it though, l1
wouldn't do anything...
What can be done to make sure that changing a Boolean in l2
doesn't tamper with l1
Example with Integers:
ArrayList<ArrayList<Integer>> l1 = new ArrayList<>();
for (var x = 0; x < 10; x ) {
l1.add(new ArrayList<>());
for (var y = 0; y < 10; y ) {
l1.get(x).add(y);
}
}
ArrayList<ArrayList<Integer>> l2 = new ArrayList<ArrayList<Integer>>(l1);
//Should not change l1
l2.get(0).add(999);
CodePudding user response:
When creating this two arrays. We are only creating two new Objects of ArrayList but not creating a new Instances of the Objects inside the List. So whatever is inside of this two ArrayLists if L1 make a change L2 will reflect the change because this two ArrayLists are referring the same Object in the Memory.
For make this work don't initialize like this way
ArrayList<ArrayList<Integer>> l2 = new ArrayList<ArrayList<Integer>>(l1);
Iterate over l1 and create new Objects.
CodePudding user response:
Copy-constructors in the Collection framework always perform a shallow copy, not a deep copy, as you've probably expected.
Javadoc of the ArrayList(Collection<? extends E> c)
says:
Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator.
Namely, the resulting list would contain exactly the same elements, not their copies. I.e. in your case, references the same inner lists.
Hence, you need to copy each element in the nested list manually:
public static <T> List<List<T>> copyNestedList(List<List<T>> list) {
List<List<T>> copy = new ArrayList<>();
for (List<T> l: list) {
copy.add(new ArrayList<>(l));
}
return copy;
}
If you're comfortable with Stream API, you can do it like that:
public static <T> List<List<T>> copyNestedList(List<List<T>> list) {
return list.stream()
.map(ArrayList::new)
.collect(Collectors.toList());
}
CodePudding user response:
You could manually create a new list without referencing the original one
ArrayList<ArrayList<Integer>> l1 = new ArrayList<>();
for (var x = 0; x < 2; x ) {
l1.add(new ArrayList<>());
for (var y = 0; y < 2; y ) {
l1.get(x).add(y);
}
}
ArrayList<ArrayList<Integer>> l2 = new ArrayList<ArrayList<Integer>>();
for (int i = 0;i < l1.size(); i ){
ArrayList<Integer> tmp = new ArrayList<Integer>();
for (int j = 0;j < l1.get(i).size(); j ){
tmp.add(l1.get(i).get(j));
}
l2.add(tmp);
}