Home > Enterprise >  How can I prevent one ArrayList changing another
How can I prevent one ArrayList changing another

Time:09-01

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);
    } 
  • Related