2013-07-26 183 views
53

我有一些問題列表副本列表:深拷貝在Python

所以我從'get_edge'得到E0後,我通過調用'E0_copy = list(E0)'使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 

提前感謝!

+1

此外,b = A [:]是一個淺合作PY。請參閱http://stackoverflow.com/questions/16270374/how-to-make-a-shallow-copy-of-a-list-in-python –

回答

103

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

Thanks.But我認爲list()是一個深層複製,因爲id( E0)不等於id(E0_copy)。你能解釋爲什麼會發生? – Shen

+6

列表(...)不會遞歸地創建內部對象的副本。它只是創建最外層列表的副本,同時仍然引用上一個變量的內層列表,因此,當您更改內層列表時,更改會反映在原始列表和淺層副本中。 –

+0

您可以看到,淺拷貝通過檢查id(a [0])== id(b [0])來引用內部列表,其中b = list(a),a是列表列表。 –

1

如果您list elementsimmutable objects那麼你可以使用它,否則,您必須使用deepcopycopy模塊。

你也可以用最短的路深副本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] 
+14

這不是Deep Copy。 –

+1

然後它是什麼。它有兩個不同的詞典(你可以檢查每個詞的ID)具有相同的值。 –

+0

閱讀[this](http://docs.python.org/2/library/copy.html),[:]只是創建一個淺拷貝,它不會遞歸地在其中創建對象的副本。 –

0

只是一個遞歸深層複製函數。

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

編輯:作爲Cfreak提到的,這已經在copy模塊來實現。

+2

沒有理由在'copy'模塊 – Cfreak

0

關於名單爲一棵樹,在Python DEEP_COPY可以最緊湊寫成

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

相信很多程序員都遇到了在那裏他們被要求深拷貝一個或兩個面試問題鏈表,但是這個問題並不像聽起來那麼簡單!

在python

,有一個被稱爲「複製」了兩個有用的功能

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

拷貝()是一個淺拷貝功能模塊中,如果給定的參數是這樣的化合物的數據結構,例如一個列表,那麼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到new_object REF」時,這防止不必要的重複,從而保持所複製的化合物的數據的結構

official doc

-1

這是更Python

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. 

注:這是不是與可變類型

+1

中重新實現標準'deepcopy()'函數,這是行不通的。我認爲這可能只是一個檢查。嘗試將字典列表作爲一個好例子 –

+0

@ShashankSingh是的,這不適用於字典列表,因爲條目是引用標籤(指向內存位置)。因此,用這種方法重複字典列表將創建一個新列表,但由於條目是字典,它們仍然會引用相同的內存位置。 –

3

列表安全如果列表中的內容是原始數據類型,你可以使用一個修真

new_list = [i for i in old_list] 

可以嵌套它像多維列表:

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