web-dev-qa-db-fra.com

Comment copier en profondeur une liste?

J'ai un problème avec une copie de la liste:

Donc, après avoir obtenu E0 de 'get_Edge', je fais une copie de E0 en appelant 'E0_copy = list(E0)'. Ici, je suppose que E0_copy est une copie complète de E0, et je passe E0_copy en 'karger(E)'. Mais dans la fonction principale.
Pourquoi le résultat de 'print E0[1:10]' avant la boucle for n'est-il pas le même que celui après la boucle for?

Ci-dessous mon 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
102
Shen

E0_copy n'est pas une copie conforme. Vous ne faites pas de copie complète avec list() (list(...) et testList[:] sont des copies superficielles).

Vous utilisez copy.deepcopy(...) pour copier en profondeur une liste.

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

Voir l'extrait suivant -

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

Voir maintenant l'opération 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]]
176
Sukrit Kalra

Je crois que beaucoup de programmeurs ont rencontré un ou deux problèmes d’interview où on leur a demandé de copier en profondeur une liste chaînée, mais ce problème est plus difficile qu’il ne le paraît!

en python, il existe un module appelé "copy" avec deux fonctions utiles

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

copy () est une fonction de copie superficielle, si l'argument donné est une structure de données composée, par exemple une liste , alors python créera un autre objet du même type (dans ce cas, une nouvelle liste ), mais pour tout ce qui est dans l'ancienne liste, seule leur référence sera copiée

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

Intuitivement, nous pourrions supposer que deepcopy () suivrait le même paradigme, et la seule différence est que pour chaque élément , nous appellerons récursivement deepcopy , ( comme la réponse de mbcoder)

mais c'est faux!

deepcopy () préserve la structure graphique des données composées originales:

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

c'est la partie la plus délicate, lors du processus de deepcopy () une hashtable (dictionnaire en python) est utilisée pour mapper: "old_object ref sur new_object ref", ceci évite les doublons inutiles et préserve ainsi la structure des données composées copiées

doc officiel

50
watashiSHUN

Si le contenu de la liste est constitué de types de données primitifs, vous pouvez utiliser une méthode de compréhension.

new_list = [i for i in old_list]

Vous pouvez l'imbriquer pour des listes multidimensionnelles comme:

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

Si votre list elements est immutable objects, vous pouvez l'utiliser, sinon vous devez utiliser le module deepcopy du copy.

vous pouvez aussi utiliser le chemin le plus court pour copier en profondeur une list comme ceci.

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

juste une fonction de copie profonde récursive.

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

Edit: Comme Cfreak l’a mentionné, cela est déjà implémenté dans le module copy.

2
rnbguy

En considérant la liste comme un arbre, la copie profonde de python peut être écrite de la manière la plus compacte:

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