2

I have written a python code, to solve a puzzle. It was not working as expected. So while debugging I saw something very weird. Row is a list of lists. The append 1 to single row[n] appends to all lists inside row!

def trap( height):
        row = []

        for index, i in enumerate(height):
            if i == 0 and len(row) == 0:
                continue
            else:
                if(i > len(row)):#time for a new row
                  #to old rows append 0 below  
                  for j in range(0, len(row)):
                        row[j].append(0)
                  row = row + [[0]] * (i - len(row))            
                else:
                  for j in range(0,i):
                     row[j].append(0)
                  #PROBLEMATIC CODE START  
                  for jo in range(i,len(row)):
                        if(index == 1):
                            print("jays are",row)
                            print("jo is",jo, row[jo])
                        row[jo].append(1)
                  #PROBLEMATIC CODE END (I GUESS?)


        print(row) #print this, it gives an idea


trap([2,0])

When I try this independently, it works fine, see:

row = [[0],[0]]
index = 1

for jo in range(0,len(row)):
      if(index == 1):
                  print("jays are",row)
                  print("jo is",jo, row[jo])
                  row[jo].append(1)
print(row)

The problematic code has been marked in the python as comment #PROBLEMATIC CODE START and #PROBLEMATIC CODE END. Call the trap() with [2,0]

row variable should be [[0,1],[0,1]] but row variable is coming [[0,1,1],[0,1,1]]

I have been at this for many hours! I just don't understand why does .append() appends to all the lists inside row, but when I try the smaller code it works. Please help me and guide me

shuberman
  • 1,416
  • 6
  • 21
  • 38
padma
  • 23
  • 3
  • 2
    The problem is the way you edited the row. **row = row + [[0]] * (i - len(row))** when using the " * " operator with list, the same object gets to be referenced several times along the row. – Seraph Wedd Aug 23 '19 at 09:12
  • 1
    Pretty sure `list.append` is working normally and your code is just confused :) You might find my [general tips on debugging small Python programs](https://stackoverflow.com/questions/52353953/my-python-code-that-converts-numbers-between-bases-has-several-errors-what-coul/52354973#52354973) helpful. In general, start from the code that *was* working, and build on it a bit at a time, making sure that each step works as you expect, rather than try to do everything at once. – Iguananaut Aug 23 '19 at 09:14

2 Answers2

8

When creating a list using *, you are just copying the reference to the object and not the instance itself. Short example:

>>> a = [["abv"]] * 3
>>> a
[['abv'], ['abv'], ['abv']]
>>> a[0].append(1)
>>> a
[['abv', 1], ['abv', 1], ['abv', 1]]

I'm creating a list which contains the object ["abv"] 3 times. It's all the same object, just 3 times in the list. As soon as I edit one item, it looks like all items are updated but actually it's all the same.

You'd need to create your list like this to create a new object for every iteration:

>>> a = [["abv"] for _ in range(3)]

So your code should be changed to this:

row += [[0] for x in range(i - len(row))]
Tim Woocker
  • 1,883
  • 1
  • 16
  • 29
4

To answer this question, you would need to modify your code a little bit.

#to old rows append 0 below  
for j in range(0, len(row)):
    row[j].append(0)
row = row + [[0]] * (i - len(row))

You need to modify it to remove the multiple reference on the same object.

#to old rows append 0 below  
for j in range(0, len(row)):
    row[j].append(0)
row += [[0] for x in range(i - len(row))]

with this, you should probably get the correct values.

Tim Woocker
  • 1,883
  • 1
  • 16
  • 29
Seraph Wedd
  • 864
  • 6
  • 14