एक सूची की गहरी नकल कैसे करें?


150

मुझे सूची की प्रतिलिपि के साथ कुछ समस्या है:

तो मुझे मिल गया के बाद E0से 'get_edge', मैं की एक प्रतिलिपि बनाने E0को फोन करके 'E0_copy = list(E0)'। यहाँ मैं अनुमान E0_copyकी गहरी प्रति है E0, और मैं पारित E0_copyमें 'karger(E)'। लेकिन मुख्य समारोह में। लूप के लिए पहले
का परिणाम 'print E0[1:10]'लूप के बाद के साथ समान क्यों नहीं है ?

नीचे मेरा कोड है:

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
इसके अलावा, b = [[:] एक उथली प्रति है। देखें stackoverflow.com/questions/16270374/...
अरविंद हरण

जवाबों:


231

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

3
धन्यवाद। लेकिन मुझे लगा कि सूची () आईडी (E0) आईडी (E0_copy) के बराबर नहीं के बाद से एक गहरी प्रतिलिपि है। क्या आप बता सकते हैं कि ऐसा क्यों होता है?
शेन

15
सूची (...) पुनरावर्ती रूप से आंतरिक वस्तुओं की प्रतियां नहीं बनाती है। यह केवल सबसे बाहरी सूची की एक प्रतिलिपि बनाता है, जबकि अभी भी पिछले चर से आंतरिक सूचियों को संदर्भित करता है, इसलिए, जब आप आंतरिक सूचियों को म्यूट करते हैं, तो परिवर्तन मूल सूची और उथले प्रतिलिपि दोनों में परिलक्षित होता है।
Sukrit Kalra

1
आप देख सकते हैं कि उथली नकल उस आईडी ([0]) == आईडी (बी [0]) की जाँच करके आंतरिक सूचियों का संदर्भ देती है जहाँ b = सूची (a) और सूचियों की सूची है।
सुक्रित कालरा

list1.append (list2) भी list2 की एक उथली प्रति है
Lazik

60

मेरा मानना ​​है कि बहुत सारे प्रोग्रामर एक या दो साक्षात्कार समस्याओं में भाग लिए हैं, जहां उन्हें एक लिंक की गई सूची की गहरी नकल करने के लिए कहा जाता है, हालांकि यह समस्या इससे कहीं अधिक कठिन है जितना लगता है!

अजगर में, दो उपयोगी कार्यों के साथ "कॉपी" नामक एक मॉड्यूल है

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

कॉपी () एक उथला कॉपी फ़ंक्शन है, यदि दिए गए तर्क एक कंपाउंड डेटा संरचना है, उदाहरण के लिए एक सूची , तो अजगर उसी प्रकार का एक और ऑब्जेक्ट (इस मामले में, एक नई सूची ) बनाएगा, लेकिन पुरानी सूची के अंदर सब कुछ के लिए, केवल उनके संदर्भ की प्रतिलिपि बनाई गई है

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

सहज रूप से, हम यह मान सकते हैं कि डीपकोपी () एक ही प्रतिमान का पालन करेगा, और केवल अंतर यह है कि प्रत्येक एलएम के लिए हम पुनरावर्ती रूप से डीकोस्कोपी कहेंगे , (बस 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'']

यह ट्रिकी पार्ट है, डीपकोपी की प्रक्रिया के दौरान () हैशटेबल (अजगर में शब्दकोष) का उपयोग मैप के लिए किया जाता है: "old_object Ref on new_object ref", यह अनावश्यक डुप्लिकेट को रोकता है और इस प्रकार कॉपी किए गए कंपाउंड डेटा की संरचना को संरक्षित करता है।

आधिकारिक डॉक्टर


18

यदि सूची की सामग्री आदिम डेटा प्रकार हैं, तो आप एक समझ का उपयोग कर सकते हैं

new_list = [i for i in old_list]

आप इसे बहुआयामी सूची के लिए घोंसला बना सकते हैं जैसे:

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

5

अपने तो list elementsकर रहे हैं immutable 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]

21
यह डीप कॉपी नहीं है।
सुकृत कालरा

1
तो यह क्या है। इसमें दो अलग-अलग शब्दकोश हैं (आप प्रत्येक की आईडी की जांच कर सकते हैं) समान मूल्यों के साथ।
दर्जी_राज

पढ़ें यह , [:] बस एक उथले कॉपी बन जाती है, यह रिकर्सिवली एक के अंदर की वस्तुओं की प्रतियां नहीं बनाता है।
सुकृत कालरा

1
धन्यवाद। आपके कहने का मतलब है कि यदि हम इसका उपयोग करते हैं, तो नई सूची बनाई जाएगी लेकिन नई सूची के सभी तत्व केवल प्रतियां ही होंगे, वे पिछले एक के समान ऑब्जेक्ट (एक ही आईडी) वाले होंगे?
दर्जी_राज

नेस्टेड सूची का उपयोग करने का प्रयास करें। सूची के नेस्टेड आइटम को अपडेट करें a। यह सूची b में भी अपडेट हो जाएगा। इसका तात्पर्य है [:] गहरी प्रति नहीं है।
अनुपमचूग

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मॉड्यूल में लागू है ।


4
मॉड्यूल deepcopy()में मानक फ़ंक्शन को फिर से लागू करने का कोई कारण नहीं हैcopy
Cfreak

1

एक पेड़ के रूप में सूची के बारे में, अजगर में डीप_कोपी सबसे कॉम्पैक्ट रूप से लिखा जा सकता है

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

0

यहां एक सूची की गहरी प्रतिलिपि बनाने का एक उदाहरण दिया गया है:

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

0

यह अधिक पायथोनिक है

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.

नोट: यह संदर्भित वस्तुओं की सूची के साथ सुरक्षित नहीं है


2
यह काम नहीं करता। मैंने सोचा कि यह हो सकता है लेकिन सिर्फ जाँच की। एक अच्छे उदाहरण के रूप में शब्दकोशों की एक सूची के साथ प्रयास करें
शशांक सिंह

@ शशांकसिंह हाँ यह शब्दकोशों की सूची के लिए काम नहीं करेगा क्योंकि प्रविष्टियाँ संदर्भ टैग हैं (किसी स्मृति स्थान की ओर इशारा करते हुए)। तो इस पद्धति के साथ शब्दकोश की एक सूची को दोहराए जाने से एक नई सूची बन जाएगी लेकिन चूंकि प्रविष्टियां शब्दकोश हैं इसलिए वे अभी भी उसी स्मृति स्थान को संदर्भित करेंगे।
क्वाव एनॉर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.