Как я могу назначить каждое переменное значение списка различным ключам одного и того же словаря? - PullRequest
2 голосов
/ 22 мая 2019

Я пытаюсь создать словарь (суммы), ключи которого - общая сумма списка, а значение - сам список. Этот список имеет различное количество элементов, но одно и то же имя. Каждый раз, когда элементы списка изменяются, и этот измененный список (с тем же именем) назначается другому ключу, также изменяется ранее назначенное значение для ключа.

В поисках подходящего ответа на этот вопрос я узнал отсюда (https://stackoverflow.com/a/52806573/7198441)), что это может быть из-за того, что Python также ссылается на списки (пожалуйста, исправьте меня, если я делаю ошибку здесь). Теперь я хочу знать , если есть способ, которым я могу назначить список, имеющий одно и то же имя, но разные элементы на разных этапах итерации, для разных ключей одного и того же словаря.

l = [1, 2, 3, 4, 5]

sums = {}

while len(l) :

    l_sum = sum(l)
    sums[l_sum] = l

    print(sums)
    print()

    l.pop()

Фактический результат:

{15: [1, 2, 3, 4, 5]}

{15: [1, 2, 3, 4], 10: [1, 2, 3, 4]}

{15: [1, 2, 3], 10: [1, 2, 3], 6: [1, 2, 3]}

{15: [1, 2], 10: [1, 2], 6: [1, 2], 3: [1, 2]}

{15: [1], 10: [1], 6: [1], 3: [1], 1: [1]}

Ожидаемое:

{15: [1, 2, 3, 4, 5]}

{15: [1, 2, 3, 4, 5], 10: [1, 2, 3, 4]}

{15: [1, 2, 3, 4, 5], 10: [1, 2, 3, 4], 6: [1, 2, 3]}

{15: [1, 2, 3, 4, 5], 10: [1, 2, 3, 4], 6: [1, 2, 3], 3: [1, 2]}

{15: [1, 2, 3, 4, 5], 10: [1, 2, 3, 4], 6: [1, 2, 3], 3: [1, 2], 1: [1]}

Ответы [ 2 ]

1 голос
/ 22 мая 2019

Проблема в том, что когда вы делаете sums[l_sum] = l, вы работаете со ссылкой на исходный список.Таким образом, все изменения на любом этапе цикла while будут влиять на все остальные места, где использовался этот список.Вот почему вы видите, что в каждом отпечатке ваш список меняется.

Простым решением является использование sums[l_sum] = l[:] для копирования списка.


while len(l) :
    l_sum = sum(l)
    sums[l_sum] = l[:] # <--- changed here from l to l[:]
    print(sums)
    print()
    l.pop()

# {15: [1, 2, 3, 4, 5]}

# {15: [1, 2, 3, 4, 5], 10: [1, 2, 3, 4]}

# {15: [1, 2, 3, 4, 5], 10: [1, 2, 3, 4], 6: [1, 2, 3]}

# {15: [1, 2, 3, 4, 5], 10: [1, 2, 3, 4], 6: [1, 2, 3], 3: [1, 2]}

# {15: [1, 2, 3, 4, 5], 10: [1, 2, 3, 4], 6: [1, 2, 3], 3: [1, 2], 1: [1]}
1 голос
/ 22 мая 2019

Вы выполняете все операции с одним экземпляром объекта списка. Вот почему в конечном результате вы получите один и тот же список для всех значений. Вместо цикла, в качестве более Pythonic способа, вы можете использовать словарное понимание или itertools.accumulate, чтобы получить накопительную сумму элементов списка, а затем использовать zip для создания ожидаемого словаря.

In [13]: {sum(l[:i + 1]): l[:i + 1] for i in range(len(l))}
Out[13]: {1: [1], 3: [1, 2], 6: [1, 2, 3], 10: [1, 2, 3, 4], 15: [1, 2, 3, 4, 5]}

Или (менее Pythonic):

In [7]: dict(zip(accumulate(l), [l[:i + 1] for i in range(len(l))]))
Out[7]: {1: [1], 3: [1, 2], 6: [1, 2, 3], 10: [1, 2, 3, 4], 15: [1, 2, 3, 4, 5]}
...