Разница между arr.append (curr) и arr.append (curr [:]) - PullRequest
3 голосов
/ 09 июля 2020

Функция производства powerset дает правильный ввод. Однако при замене append (curr [:]) на append (curr) выдает список пустых списков. В чем причина?

def subsets(nums):
    def backtrack(first = 0, curr = []):
        # if the combination is done
        if len(curr) == k:  
            output.append(curr)
            return
        for i in range(first, n):
            # add nums[i] into the current combination
            curr.append(nums[i])
            # use next integers to complete the combination
            backtrack(i + 1, curr)
            # backtrack
            curr.pop()
    
    output = []
    n = len(nums)
    for k in range(n + 1):
        backtrack()
    return output

Ответы [ 3 ]

4 голосов
/ 09 июля 2020

Как отмечали другие ответы, cur[:] делает копию cur. Без создания копии output заканчивается тем, что содержит множество копий одного и того же списка - каждый из этих списков изменяется каждый раз, когда вы вызываете cur.append или cur.pop.

Списки заканчиваются пустыми , потому что для каждого вызова cur.append существует один вызов cur.pop, что гарантирует, что «последняя» итерация cur будет пустой.

2 голосов
/ 09 июля 2020

Разница между arr.append(curr) и arr.append(curr[:]) заключается в том, что первый копирует адрес списка curr в arr, а второй копирует значения curr в arr.

Давайте посмотрим на разницу на примерах.

Первый сценарий:

curr = [5, 10, 15, 20]
arr = []
arr.append(curr)
print("Before update")
print("Curr: {}\nArr: {}".format(curr, arr))
curr[1] = 7
print("After update")
print("Curr: {}\nArr: {}".format(curr, arr))

Вывод:

Before update
Curr: [5, 10, 15, 20]
Arr: [[5, 10, 15, 20]]
After update
Curr: [5, 7, 15, 20]
Arr: [[5, 7, 15, 20]]

Второй сценарий:

curr = [5, 10, 15, 20]
arr = []
print("Before update")
arr.append(curr[:])
print("Curr: {}\nArr: {}".format(curr, arr))
curr[1] = 7
print("After update")
print("Curr: {}\nArr: {}".format(curr, arr))

Вывод :

Before update
Curr: [5, 10, 15, 20]
Arr: [[5, 10, 15, 20]]
After update
Curr: [5, 7, 15, 20]
Arr: [[5, 10, 15, 20]]

Как вы можете видеть в первом сценарии, как curr, так и arr обновляются при изменении одного значения индекса в списке curr. Поскольку добавление curr к arr содержит тот же адрес памяти.

Во втором сценарии только curr обновляется при изменении одного значения индекса в списке curr. Поскольку добавление [:] к arr копирует содержимое из списка curr в список arr.

Согласно сказанному выше (теория), причина, по которой вы получаете [[], [], [], [], [], [], [], []] при запуске изменение кода curr на curr[:] связано с тем, что в последней строке curr.pop() в функции backtrack вы удаляете последние элементы один за другим, поэтому вы удаляете элементы из списка, который все время находится в одной и той же пространственной памяти, а не из ее значений из списка копий.

1 голос
/ 09 июля 2020

Использование arr.append(curr[:]) означает добавление COPY из curr, а arr.append(curr) добавляет curr себя к массиву arr, что означает, что когда вы вносите какие-либо изменения в curr, это значение в arr также изменится соответственно

Подробнее о копировании массива читайте здесь: Ссылка

...