1

Uber-newb question. I thought I was over this, but I am stuck.

First I have I'll tell you what I am trying to achieve. Newbie Challenge question. (credit: V. Anton Spraul)

You'll see from the picture that I am trying to create a 3 digit unique code (corresponding to Fire, Police, Sanitation), that adds to 12 and that the middle digit (Police) is always even.

I know there is a brute force way of doing this but I didn't want to take that approach. I thought I'd take the slightly more difficult but hopefully efficient way by stacking 3 for loops. But I am stuck at a very early stage and can't understand the logic of what's going on. Here's my code:

highestdigit=7
department_number=[0,0,0]
department_numbers=[]

for number in range(1,highestdigit+1):
    #Fire, Police, Sanitation
    #Numbering the Police dept
    if number %2 == 0:
        department_number[1]=number
        department_numbers.append(department_number)

    else:
        pass
print(department_numbers)

What I am expecting from this is:

[[0,2,0,],[0,4,0],[0,6,0]]

What I getting is:

[[0,6,0,],[0,6,0],[0,6,0]]

Why is this? Why am I getting the max value digit in the range, and why 3 times?

Also if I try to place the print command within the loop, it

highestdigit=7
department_number=[0,0,0]
department_numbers=[]

for number in range(1,highestdigit+1):
    #Fire, Police, Sanitation
    #Numbering the Police dept
    if number %2 == 0:
        department_number[1]=number
        department_numbers.append(department_number)
        print(department_numbers)
    else:
        pass

What I was expecting from this:

[[0,2,0]]
[[0,2,0],[0,4,0]]
[[0,2,0],[0,4,0],[0,6,0]]

i.e. that it would build the list of lists that I want, step by step, printing each step.

Instead, what I got is:

[[0, 2, 0]]
[[0, 4, 0], [0, 4, 0]]
[[0, 6, 0], [0, 6, 0], [0, 6, 0]]

I am pretty baffled why either of these outcomes are occurring.

Mike Müller
  • 82,630
  • 20
  • 166
  • 161
Westworld
  • 190
  • 1
  • 2
  • 14
  • 2
    Possible duplicate of [How to clone or copy a list?](https://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list) – Aran-Fey Jan 27 '18 at 12:11
  • Change `department_numbers.append(department_number)` to `department_numbers.append(department_number.copy())` – Aran-Fey Jan 27 '18 at 12:12
  • Thanks. I have looked at that, but I don't see how copying a list helps to explain the logic of these outputs. – Westworld Jan 27 '18 at 12:15
  • 1
    When you change the value `department_number[1] = number`, it changes the values of all lists you appended to `department_numbers`. Meaning what you append isn't a copy of the list but a reference to the list. – Silver Jan 27 '18 at 12:20
  • `department_numbers.append(department_number)` pushes the same list, not a copy of the list. All of `department_numbers[i]` and `department_number` end up referring to the same list. – melpomene Jan 27 '18 at 12:22

1 Answers1

2

You use the same sublist department_number in each loop. Moving the creation of the sublist into the loop gives you a new each time:

highestdigit = 7
department_numbers = []

for number in range(1, highestdigit + 1):
    #Fire, Police, Sanitation
    #Numbering the Police dept
    if number %2 == 0:
        department_number = [0, 0, 0]
        department_number[1] = number
        department_numbers.append(department_number)
print(department_numbers)

Output:

[[0, 2, 0], [0, 4, 0], [0, 6, 0]]

Or simplified:

for number in range(1, highestdigit + 1):
    #Fire, Police, Sanitation
    #Numbering the Police dept
    if number %2 == 0:
        department_numbers.append([0, number, 0])

You can also turn this into a list comprehension:

department_numbers = [[0, number, 0] for number in range(1, highestdigit + 1) 
                      if number % 2 == 0 ]
Mike Müller
  • 82,630
  • 20
  • 166
  • 161