How to Deep Copy a List

How to deep copy a list?

E0_copy is not a deep copy. You don't make a deep copy using list(). (Both list(...) and testList[:] are shallow copies.)

You use copy.deepcopy(...) for deep copying a list.

deepcopy(x, memo=None, _nil=[])
Deep copy operation on arbitrary Python objects.

See the following snippet -

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b # b changes too -> Not a deepcopy.
[[1, 10, 3], [4, 5, 6]]

Now see the deepcopy operation

>>> import copy
>>> b = copy.deepcopy(a)
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]
>>> a[0][1] = 9
>>> a
[[1, 9, 3], [4, 5, 6]]
>>> b # b doesn't change -> Deep Copy
[[1, 10, 3], [4, 5, 6]]

To explain, list(...) does not recursively make copies of the inner objects. It only makes a copy of the outermost list, while still referencing the same inner lists, hence, when you mutate the inner lists, the change is reflected in both the original list and the shallow copy. You can see that shallow copying references the inner lists by checking that id(a[0]) == id(b[0]) where b = list(a).

deep copy of list in python

Your code does indeed succeed in creating a shallow copy. This can be seen by inspecting the IDs of the two outer lists, and noting that they differ.

>>> id(l)
140505607684808

>>> id(x)
140505607684680

Or simply comparing using is:

>>> x is l
False

However, because it is a shallow copy rather than a deep copy, the corresponding elements of the list are the same object as each other:

>>> x[0] is l[0]
True

This gives you the behaviour that you observed when the sub-lists are appended to.

If in fact what you wanted was a deep copy, then you could use copy.deepcopy. In this case the sublists are also new objects, and can be appended to without affecting the originals.

>>> from copy import deepcopy

>>> l=[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

>>> xdeep = deepcopy(l)

>>> xdeep == l
True

>>> xdeep is l
False <==== A shallow copy does the same here

>>> xdeep[0] is l[0]
False <==== But THIS is different from with a shallow copy

>>> xdeep[0].append(10)

>>> print(l)
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

>>> print(xdeep)
[[1, 2, 3, 10], [4, 5, 6], [7, 8, 9]]

If you wanted to apply this in your function, you could do:

from copy import deepcopy

def processed(matrix,r,i):
new_matrix = deepcopy(matrix)
new_matrix[r].append(i)
return new_matrix

l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
x = processed(l,0,10)
print(x)
print(l)

If in fact you know that the matrix is always exactly 2 deep, then you could do it more efficiently than using deepcopy and without need for the import:

def processed(matrix,r,i):
new_matrix = [sublist[:] for sublist in matrix]
new_matrix[r].append(i)
return new_matrix

l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
x = processed(l,0,10)
print(x)
print(l)

Deep copy nested list without using the deepcopy function

My entry to simulate copy.deepcopy:

def deepcopy(obj):
if isinstance(obj, dict):
return {deepcopy(key): deepcopy(value) for key, value in obj.items()}
if hasattr(obj, '__iter__'):
return type(obj)(deepcopy(item) for item in obj)
return obj

The strategy: iterate across each element of the passed-in object, recursively descending into elements that are also iterable and making new objects of their same type.

I make no claim whatsoever that this is comprehensive or without fault [1] (don't pass in an object that references itself!) but should get you started.

[1] Truly! The point here is to demonstrate, not cover every possible eventuality. The source to copy.deepcopy is 50 lines long and it doesn't handle everything.

Deep copy vs. List Comprehension

The sallow copy that happening by copy = [x for x in nested_list] is creating a new object of copy with a different id() then nested_list but all the nested lists inside of it have the same id's as the lists inside both of the lists.

nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
copy = [x for x in nested_list]
print(id(copy)) #54769064
print(id(nested_list)) #54546184
print([id(i) for i in copy]) #[58832096, 58831816, 58619384]
print([id(i) for i in nested_list]) #[58832096, 58831816, 58619384]

When doing deep copy copy = deepcopy(nested_list) the copy nested lists while creating new lists with new id's that when assigning a new value to one of the nested lists like copy[0][1] = 9999999 will change only the copy first list item and not the nested_list[0][1] value.

nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
copy = deepcopy(nested_list)
copy[0][1] = 9999999
print(copy) #[[1, 9999999, 3], [4, 5, 6], [7, 8, 9]]
print(nested_list) #[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

How to make a deep copy of an object with a List variable in Java?

Your copy constructors are just doing shallow copies of each field. That's fine for strings because they're immutable, and it's fine for ints because they're primitive (which means they lack identity and are immutable). In those cases, there is no important difference between shallow and deep copies. But it doesn't work in general for lists because lists can be mutable and so can their elements. So instead of just pointing at the same list, you need to make a new list and deep copy each element of the original list into the new one.

Use this helper method to make deep copies of any lists:

static <T> List<T> deepCopyList(List<T> list, UnaryOperator<T> deepCopyElement) {
return list.stream().map(deepCopyElement).collect(
Collectors.toCollection(ArrayList::new)
);
}

Like so:

public AtomDTO(AtomDTO that) {
this(that.getName(), that.getType(), deepCopyList(that.getBonds(), BondDTO::new));
}

How do I clone a list so that it doesn't change unexpectedly after assignment?

new_list = my_list doesn't actually create a second list. The assignment just copies the reference to the list, not the actual list, so both new_list and my_list refer to the same list after the assignment.

To actually copy the list, you have several options:

  • You can use the builtin list.copy() method (available since Python 3.3):

    new_list = old_list.copy()
  • You can slice it:

    new_list = old_list[:]

    Alex Martelli's opinion (at least back in 2007) about this is, that it is a weird syntax and it does not make sense to use it ever. ;) (In his opinion, the next one is more readable).

  • You can use the built in list() constructor:

    new_list = list(old_list)
  • You can use generic copy.copy():

    import copy
    new_list = copy.copy(old_list)

    This is a little slower than list() because it has to find out the datatype of old_list first.

  • If you need to copy the elements of the list as well, use generic copy.deepcopy():

    import copy
    new_list = copy.deepcopy(old_list)

    Obviously the slowest and most memory-needing method, but sometimes unavoidable. This operates recursively; it will handle any number of levels of nested lists (or other containers).

Example:

import copy

class Foo(object):
def __init__(self, val):
self.val = val

def __repr__(self):
return f'Foo({self.val!r})'

foo = Foo(1)

a = ['foo', foo]
b = a.copy()
c = a[:]
d = list(a)
e = copy.copy(a)
f = copy.deepcopy(a)

# edit orignal list and instance
a.append('baz')
foo.val = 5

print(f'original: {a}\nlist.copy(): {b}\nslice: {c}\nlist(): {d}\ncopy: {e}\ndeepcopy: {f}')

Result:

original: ['foo', Foo(5), 'baz']
list.copy(): ['foo', Foo(5)]
slice: ['foo', Foo(5)]
list(): ['foo', Foo(5)]
copy: ['foo', Foo(5)]
deepcopy: ['foo', Foo(1)]

How to deep copy a List<Object>

You need to implement a correct clone() method like

public class Student implements Cloneable {
public int id;
public String name;
public List<Integer> score;
public Address address;

......

@Override
protected Object clone() throws CloneNotSupportedException {
Student std = new Student();
std.id = this.id; // Immutable
std.name = this.name; // Immutable
std.score = this.score.stream().collect(Collectors.toList()); // Integer is immutable
std.address = (Adress) this.address.clone();
return std;
}

Is there any better deep clone methods for list?

That's not a real deep-copy because the Card instances are still the same, only the list is different. You could have this much simpler:

List<Card> cloneList = cards.ToList();

You need to "copy" all properties of the Card instances as well:

public List<Card> Copy(List<Card> cards)
{
List<Card> cloneList = new List<Card>();
foreach (var card in cards)
{
Card clone = new Card();
clone.Property1 = card.Property1;
// ... other properties
cloneList.Add(clone);
}
return cloneList;
}

You could also provide a factory method that creates a clone of a given Card instance:

public class Card
{
// ...

public Card GetDeepCopy()
{
Card deepCopy = new Card();
deepCopy.Property1 = this.Property1;
// ...
return deepCopy;
}
}

Then you have encapsulated this logic in one place where you can even access private members(fields, properties, constructors). Change the line in the Copy method above to:

cloneList.Add(card.GetDeepCopy()); 

java: best way to do deep copy of list of lists

Is this a good way to do?

It's fine.

Is it possible to get rid of the inner loop?

Yes, you can use the ArrayList copy constructor:

for( List<Integer> sublist : src) {
dest.add(new ArrayList<>(sublist));
}

The fact is that each of the inner sub-lists can grow to large lengths.

The above will shorten the code, and it delegates to System.arraycopy, which will likely improve performance somewhat. It also avoids the repeated resize/copy when you fill an empty ArrayList. But there's fundamentally no way to avoid the O(n) time complexity of copying a list/array, if you truly need a deep copy. Since you don't explain why you need a deep copy, I'll have to take you at your word.



Related Topics



Leave a reply



Submit