Подтвердить что ты не робот

Как глубоко скопировать список?

У меня есть некоторые проблемы с копией списка:

Поэтому после того, как я получил 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
4b9b3361

Ответ 1

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

Ответ 2

Я полагаю, что многие программисты сталкиваются с одной или двумя проблемами интервью, когда их просят глубоко скопировать связанный список, однако эта проблема сложнее, чем кажется!

в python есть модуль с именем "copy" с двумя полезными функциями

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

copy() - это функция мелкого копирования, если данный аргумент является составной структурой данных, например, списком, то python создаст другой объект того же типа (в данном случае, новый список), но для всего внутри старого списка, копируется только их ссылка

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

Интуитивно, мы могли бы предположить, что deepcopy() будет следовать той же парадигме, и единственное отличие состоит в том, что для каждого элемента мы будем рекурсивно называть deepcopy (так же, как ответ mbcoder)

но это неправильно!

deepcopy() фактически сохраняет графическую структуру исходных составных данных:

a = [1,2]
b = [a,a] # there 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 to new_object ref", это предотвращает ненужные дубликаты и, таким образом, сохраняет структуру скопированных составных данных

официальный документ

Ответ 3

Если содержимое списка является примитивным типом данных, вы можете использовать понимание

new_list = [i for i in old_list]

Вы можете вложить его в многомерные списки, например:

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

Ответ 4

Если ваш list elements immutable objects, вы можете использовать его, иначе вам нужно использовать модуль deepcopy из copy.

вы также можете использовать самый короткий путь для глубокой копии a 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]

Ответ 5

просто рекурсивная функция глубокой копии.

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

Изменить: Как упоминал Cfreak, это уже реализовано в модуле copy.

Ответ 6

Что касается списка как дерева, то deep_copy в python может быть наиболее компактно записан как

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

Ответ 7

Это более питонический

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.

ПРИМЕЧАНИЕ: это не безопасно со списком изменяемых типов