问题:如何深层复制列表?

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

所以之后我得到了E0来自'get_edge',我做的副本E0通过调用'E0_copy = list(E0)'。我想E0_copy是这里的深复制E0,我E0_copy走进了'karger(E)'。但是在主要功能上。
为什么'print E0[1:10]'for循环之前的结果与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

I have some problem with a List copy:

So After I got E0 from 'get_edge', I make a copy of E0 by calling 'E0_copy = list(E0)'. Here I guess E0_copy is a deep copy of E0, and I pass E0_copy into 'karger(E)'. But in the main function.
Why does the result of 'print E0[1:10]' before the for loop is not the same with that after the for loop?

Below is my code:

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

回答 0

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

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

回答 1

我相信很多程序员遇到一个或两个面试问题,他们被要求深度复制链表,但是这个问题比听起来要难!

在python中,有一个名为“ copy”的模块,具有两个有用的功能

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

如果给定参数是复合数据结构,例如,则copy()是浅表复制函数。 list,则python将创建另一个相同类型的对象(在这种情况下为new list),但对于旧列表中的所有对象,仅复制他们的参考

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

直观地,我们可以假定deepcopy()遵循相同的范例,唯一的区别是对于每个元素,我们将递归调用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到new_object ref”,这可以防止不必要的重复,从而保留复制的复合数据的结构

官方文件

I believe a lot of programmers have run into one or two interview problems where they are asked to deep copy a linked list, however this problem is harder than it sounds!

in python, there is a module called “copy” with two useful functions

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

copy() is a shallow copy function, if the given argument is a compound data structure, for instance a list, then python will create another object of the same type (in this case, a new list) but for everything inside old list, only their reference is copied

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

Intuitively, we could assume that deepcopy() would follow the same paradigm, and the only difference is that for each elem we will recursively call deepcopy, (just like the answer of mbcoder)

but this is wrong!

deepcopy() actually preserve the graphical structure of the original compound data:

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

this is the tricky part, during the process of deepcopy() a hashtable(dictionary in python) is used to map: “old_object ref onto new_object ref”, this prevent unnecessary duplicates and thus preserve the structure of the copied compound data

official doc


回答 2

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

new_list = [i for i in old_list]

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

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

If the contents of the list are primitive data types, you can use a comprehension

new_list = [i for i in old_list]

You can nest it for multidimensional lists like:

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

回答 3

如果list elements是,immutable objects则可以使用它,否则必须使用deepcopyfrom 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]

If your list elements are immutable objects then you can use this, otherwise you have to use deepcopy from copy module.

you can also use shortest way for deep copy a list like this.

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

只是递归的深层复制功能。

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

编辑:正如Cfreak所述,这已经在copy模块中实现。

just a recursive deep copy function.

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

Edit: As Cfreak mentioned, this is already implemented in copy module.


回答 5

关于列表作为树,Python中的deep_copy可以写成最紧凑的形式:

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

Regarding the list as a tree, the deep_copy in python can be most compactly written as

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

回答 6

这是如何深度复制列表的示例:

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

Here’s an example of how to deep copy a 2D list:

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

回答 7

这更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.

注意:这是不安全的引用对象的列表

This is more 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.

NOTE: This is not safe with a list of referenced objects


声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。