0

I am trying to append a list into another list however I cannot seem to make it work.

Here is the code. When I run it and print Q for each iteration of the while loop I get something like [2,3] [2] [3,4] etc. And I want to append these lists into the list my_Q by doing my_Q.append(Q). However, this returns me this: my_Q = [0, [], [], [] ]

import random

#Matrix Input
M = 10**3

G = [   [M, 5, 9, M],
        [M, M, 1, 10],
        [M, M, M, 4],
        [M, M ,M, M]    ]

#Initialize
Q = [1]
l = [0, M, M, M]
A = [1, 2, 3, 4]
iter = 0

#For display
my_v = [0]
my_Q = [1]

#Algorithm
while Q:        #Stop conditions
    
    iter += 1

    #Step 2:
    v = random.choice(Q)
    Q.remove(v)

    #Step 3:
    for w in A:
        l_new = min(l[w-1], l[v-1] + G[v-1][w-1])
        if l_new != l[w-1]:
            if w not in Q:
                Q.append(w)
            l[w-1] = l_new

    #Save for display
    my_v.append(v)
    
    print(Q)
    my_Q.append(Q)

print(my_Q)

gapansi
  • 105
  • 2
  • 10

1 Answers1

2

You have a aliasing issue. Python obfuscates the implementation from you, however appending a list to another list only adds a reference, not the values of the list.

Try this simple code:

l = []
a = [1, 2]
l.append(a)
a.remove(1)
l.append(a)
print(l)

output

[[2], [2]]

In this example, you're expecting something like [[1, 2], [2]] however since a is simply a reference in l, calling remove on 1 will remove it from a both the external variable, and its reference in the list l.

You can import copy and append a deep copy of your list instead.

import copy
import random

# Matrix Input
M = 10 ** 3

G = [[M, 5, 9, M],
     [M, M, 1, 10],
     [M, M, M, 4],
     [M, M, M, M]]

# Initialize
Q = [1]
l = [0, M, M, M]
A = [1, 2, 3, 4]
iter = 0

# For display
my_v = [0]
my_Q = [1]

# Algorithm
while Q:  # Stop conditions

    iter += 1

    # Step 2:
    v = random.choice(Q)
    Q.remove(v)

    # Step 3:
    for w in A:
        l_new = min(l[w - 1], l[v - 1] + G[v - 1][w - 1])
        if l_new != l[w - 1]:
            if w not in Q:
                Q.append(w)
            l[w - 1] = l_new

    # Save for display
    my_v.append(v)

    print(Q)
    my_Q.append(copy.deepcopy(Q))

print(my_Q)

output

[1, [2, 3], [3, 4], [3], [4], []]

I don't necessarily know what your algorithm is trying to accomplish, but this will append the current state of Q to my_Q on each iteration, and not allow calls to remove to modify the instances of Q already in the list.

If you didn't want to use deepcopy from copy, you could use slice notation to make your copy.

# my_Q.append(copy.deepcopy(Q))
my_Q.append(Q[:])
Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
  • That works perfect thanks a lot! I still don't understand what the issue is actually – gapansi Mar 30 '21 at 21:10
  • Thank you for your thorough attempt at an answer; however, this is a common problem that is best resolved by referring to the linked duplicate (possibly with a short explanatory comment). Also, please don't talk about "pointers" when discussing Python code; that's not an abstraction we actually use in Python. There is an *aliasing* issue here, yes, but it results from the list storing the same list object in multiple places. We sometimes say "reference" when we talk about the under-the-hood details of how the list works, but not "pointer" (unless we are working on the C implementation). – Karl Knechtel Mar 30 '21 at 21:11
  • 1
    OP: if you want to "understand what the issue is", you should read the linked duplicate. – Karl Knechtel Mar 30 '21 at 21:12