Bir liste nasıl derin kopyalanır?


150

Liste kopyasıyla ilgili bir sorunum var:

Ben aldıktan sonra Yani E0gelen 'get_edge', ben bir kopyasını E0arayarak 'E0_copy = list(E0)'. Burada tahminim E0_copyderin bir kopyasıdır E0ve ben geçmesi E0_copyhalinde 'karger(E)'. Ama ana işlevde.
Neden 'print E0[1:10]'for döngüsünden önceki sonuç for döngüsünden sonraki ile aynı değil?

Kodum aşağıdadır:

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

2
Ayrıca, b = a [:] sığ bir kopyadır. Bkz stackoverflow.com/questions/16270374/…
Arvind Haran

Yanıtlar:


231

E0_copyderin bir kopya değildir. Sen kullanarak derin bir kopyasını yapmazlar list()(Hem list(...)ve testList[:]sığ kopyalarıdır).

copy.deepcopy(...)Bir listenin derin kopyalanması için kullanılır .

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

Aşağıdaki snippet'e bakın -

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

Şimdi deepcopyoperasyona bakın

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

3
Ama id (E0) id (E0_copy) 'a eşit olmadığından list ()' in derin bir kopya olduğunu düşündüm. Neden olduğunu açıklayabilir misiniz?
Shen

15
list (...) iç nesnelerin özyineli olarak kopyalarını çıkarmaz. Yalnızca en dıştaki listenin bir kopyasını oluşturur, yine de önceki değişkenin iç listelerine başvururken, iç listeleri değiştirdiğinizde, değişiklik hem orijinal listeye hem de sığ kopyaya yansıtılır.
Sukrit Kalra

1
Sığ kopyalamanın, b = list (a) ve a'nın bir liste listesindeki id (a [0]) == id (b [0]) öğesini kontrol ederek iç listelere başvurduğunu görebilirsiniz.
Sukrit Kalra

list1.append (list2) ayrıca list2'nin sığ bir kopyasıdır
Lazik

60

Bir çok programcının bağlantılı bir listeyi derinlemesine kopyalamaları istendiğinde bir veya iki röportaj problemi yaşadıklarına inanıyorum, ancak bu sorun göründüğünden daha zor!

python'da, iki yararlı fonksiyona sahip "kopya" adında bir modül var

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

copy () sığ bir kopyalama işlevidir; verilen bağımsız değişken bir bileşik veri yapısı, örneğin bir liste ise , python aynı türden (bu durumda yeni bir liste ) başka bir nesne oluşturur, ancak eski listedeki her şey için, sadece referansları kopyalanır

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

Sezgisel olarak, deepcopy'nin () aynı paradigmayı izleyeceğini varsayabiliriz ve tek fark, her elem için tekrarlayan olarak deepcopy diyeceğimizdir (mbcoder'ın cevabı gibi).

ama bu yanlış!

deepcopy () aslında orijinal bileşik verilerin grafik yapısını korur:

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

bu zor kısımdır, deepcopy () işlemi sırasında bir hashtable (python'da sözlük) eşlemek için kullanılır: "old_object ref to new_object ref", bu gereksiz kopyaları önler ve böylece kopyalanan bileşik verilerin yapısını korur

resmi doktor


18

Listenin içeriği ilkel veri türüyse, bir anlama kullanabilirsiniz

new_list = [i for i in old_list]

Aşağıdaki gibi çok boyutlu listeler için iç içe yerleştirebilirsiniz:

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

5

Eğer senin list elementsolan immutable objectso zaman başka türlü kullanmak zorunda kullanabilir deepcopygelen copymodül.

bunun listgibi derin kopyalar için de en kısa yolu kullanabilirsiniz .

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]

21
Bu bir Derin Kopya değil.
Sukrit Kalra

1
O zaman ne. Aynı değerlere sahip iki farklı sözlük (her birinin kimliğini kontrol edebilirsiniz) vardır.
tailor_raj

Bunu okuyun , [:] sadece sığ bir kopya oluşturur, tek tek içindeki nesnelerin kopyalarını tekrar tekrar oluşturmaz.
Sukrit Kalra

1
Teşekkürler. Bunu kullanırsak, yeni liste oluşturulacak, ancak yeni listenin tüm öğeleri yalnızca kopya olacak, bir öncekiyle aynı nesneye (aynı kimlik) sahip olacaklarını mı söylüyorsunuz?
tailor_raj

Yuvalanmış bir liste kullanmayı deneyin. Listenin yuvalanmış öğesini güncelleyin a. Liste b'de de güncellenir. Bu, [:] derin bir kopya olmadığını gösterir.
AnupamChugh

2

sadece özyinelemeli derin kopyalama işlevi.

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

Düzenleme: Cfreak belirtildiği gibi, bu zaten copymodülde uygulanmaktadır .


4
Standart yeniden uygulamaya neden yok deepcopy()işlevi copymodülü
Cfreak

1

Liste bir ağaç olarak bakıldığında, python'daki deep_copy en kompakt şekilde yazılabilir

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

0

Bir listenin nasıl derin kopyalanacağına ilişkin bir örnek:

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

0

Bu daha pitonik

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.

Not: Bu başvurulan nesnelerin bir listesi ile güvenli değil


2
Bu çalışmıyor. Olabilir ama sadece kontrol düşündüm. İyi bir örnek olarak sözlüklerin bir listesini deneyin
Shashank Singh

@ShashankSingh evet, girişler referans etiketleri olduğu için (bir bellek konumuna işaret eder) bu sözlükler listesi için çalışmaz. Bu nedenle, bu yöntemle sözlük listesinin çoğaltılması yeni bir liste oluşturur, ancak girişler sözlük olduğundan, aynı bellek konumuna başvururlar.
Kwaw Annor
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.