如何深层复制列表?

时间:2013-07-26 05:12:20

标签: python list copy deep-copy

我对列表副本有一些问题:

所以,当我从E0获得'get_edge'后,我会通过调用E0复制'E0_copy = list(E0)'。我想E0_copyE0的深层副本,我将E0_copy传递给'karger(E)'。但在主要功能。
为什么for循环之前'print E0[1:10]'的结果与for循环之后的结果不一样?

以下是我的代码:

def get_graph():
    f=open('kargerMinCut.txt')
    G={}
    for line in f:
        ints = [int(x) for x in line.split()]
        G[ints[0]]=ints[1:len(ints)]
    return G

def get_edge(G):
    E=[]
    for i in range(1,201):
        for v in G[i]:
            if v>i:
                E.append([i,v])
    print id(E)
    return E

def karger(E):
    import random
    count=200 
    while 1:
        if count == 2:
            break
        edge = random.randint(0,len(E)-1)
        v0=E[edge][0]
        v1=E[edge][1]                   
        E.pop(edge)
        if v0 != v1:
            count -= 1
            i=0
            while 1:
                if i == len(E):
                    break
                if E[i][0] == v1:
                    E[i][0] = v0
                if E[i][1] == v1:
                    E[i][1] = v0
                if E[i][0] == E[i][1]:
                    E.pop(i)
                    i-=1
                i+=1

    mincut=len(E)
    return mincut


if __name__=="__main__":
    import copy
    G = get_graph()
    results=[]
    E0 = get_edge(G)
    print E0[1:10]               ## this result is not equal to print2
    for k in range(1,5):
        E0_copy=list(E0)         ## I guess here E0_coypy is a deep copy of E0
        results.append(karger(E0_copy))
       #print "the result is %d" %min(results)
    print E0[1:10]               ## this is print2

10 个答案:

答案 0 :(得分:164)

E0_copy不是深层副本。您没有使用list()制作深层副本(list(...)testList[:]都是浅层副本)。

您使用copy.deepcopy(...)深层复制列表。

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

请参阅以下代码段 -

>>> 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]]

现在看deepcopy操作

>>> 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]]

答案 1 :(得分:45)

我相信很多程序员遇到了一两个面试问题,他们被要求深层复制一个链表,但这个问题并不像听起来那么简单!

在python中,有一个名为“copy”的模块,它有两个有用的函数

import copy
copy.copy()
copy.deepcopy()

copy()是一个浅复制函数,如果给定的参数是复合数据结构,例如 list ,那么python将创建另一个相同类型的对象(在本例中为新列表)但是对于旧列表中的所有内容,只会复制其引用

# think of it like
newList = [elem for elem in oldlist]

直观地说,我们可以假设deepcopy()将遵循相同的范例,唯一的区别是每个 elem我们将递归调用deepcopy ,(就像mbcoder的答案一样)

但这是错误的!

deepcopy()实际上保留了原始化合物数据的图形结构:

a = [1,2]
b = [a,a] # there's only 1 object a
c = deepcopy(b)

# check the result
c[0] is a # return False, a new object a' is created
c[0] is c[1] # return True, c is [a',a'] not [a',a'']

这是一个棘手的部分,在deepcopy()过程中,一个哈希表(python中的字典)用于映射: “old_object ref into new_object ref”,这可以防止不必要的重复,从而保留复制的复合数据的结构

official doc

答案 2 :(得分:7)

如果列表的内容是原始数据类型,则可以使用理解

new_list = [i for i in old_list]

您可以将其嵌套为多维列表,例如:

new_grid = [[i for i in row] for row in grid]

答案 3 :(得分:2)

如果您的list elementsimmutable objects,那么您可以使用此功能,否则您必须使用deepcopy模块中的copy

您还可以使用最短的方式进行深度复制list

a = [0,1,2,3,4,5,6,7,8,9,10]
b = a[:] #deep copying the list a and assigning it to b
print id(a)
20983280
print id(b)
12967208

a[2] = 20
print a
[0, 1, 20, 3, 4, 5, 6, 7, 8, 9,10]
print b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10]

答案 4 :(得分:2)

只是递归深层复制功能。

def deepcopy(A):
    rt = []
    for elem in A:
        if isinstance(elem,list):
            rt.append(deepcopy(elem))
        else:
            rt.append(elem)
    return rt

编辑:正如Cfreak所提到的,这已在copy模块中实现。

答案 5 :(得分:1)

关于作为树的列表,python中的deep_copy可以最紧凑地写为

def deep_copy(x):
    if not isinstance(x, list): return x
    else: return map(deep_copy, x)

答案 6 :(得分:0)

下面是如何深度复制2D列表的示例:

  b = [x[:] for x in a]

答案 7 :(得分:0)

@Sukrit Kalra 我在Python3.9.0中找到了这个。

No.1:list()将生成一个新列表,更新原始列表不会更改新列表。
No.2:直接let avgArray = []; let sum = 0; for (let i = 0; i < data.length; i ++) { let parsed = parseInt(data[i].age); sum += parsed; avgArray.push(parsed); } let avg = sum / avgArray.length; b = aa具有相同的引用,更改b就像更改a一样。

b

答案 8 :(得分:-1)

这更像是pythonic

my_list = [0, 1, 2, 3, 4, 5]  # some list
my_list_copy = list(my_list)  # my_list_copy and my_list does not share reference now.

注意:对于可变类型列表

,这是不安全的

答案 9 :(得分:-1)

如果不允许直接导入模块,可以将自己的 deepcopy 函数定义为 -

def copyList(L):
if type(L[0]) != list:
    return [i for i in L]
else:
    return [copyList(L[i]) for i in range(len(L))]

它的工作可以很容易地被视为 -

>>> x = [[1,2,3],[3,4]]
>>> z = copyList(x)
>>> x
[[1, 2, 3], [3, 4]]
>>> z
[[1, 2, 3], [3, 4]]
>>> id(x)
2095053718720
>>> id(z)
2095053718528
>>> id(x[0])
2095058990144
>>> id(z[0])
2095058992192
>>>