1

I am creating code that calculates neighbor coordinates to passed coordinate.

I have list of lists with "directions" I want move to, first number is X-value, second number is Y-value.

directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]

Then I have a function to calculate new coordinates and store them in a list "results"

results = []

def NeighborsFinder(coordinate):
    originalCoordinate = coordinate
    for x in range(0, len(directions)):
        coordinate[0] += directions[x][0]
        coordinate[1] += directions[x][1]
        results.append(coordinate)
        print(coordinate)
        coordinate = originalCoordinate

Example: if I pass coordinate [2, 3]

Then correct output should be list with coordinates: [2, 4] [2, 2], [3, 3], [1, 3]

Well but what happens to me is that its adding +1, but not substracting -1 so my output look like this: [2, 4], [2, 3], [3, 3], [2, 3].

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
matuh
  • 13
  • 2
  • The problem is that you actively modify `coordinate`. So instead of always starting from [2,3], you start from the previously calculated value. – Stef Dec 13 '21 at 13:25
  • 1
    Does this answer your question? [List changes unexpectedly after assignment. Why is this and how can I prevent it?](https://stackoverflow.com/questions/2612802/list-changes-unexpectedly-after-assignment-why-is-this-and-how-can-i-prevent-it) – mkrieger1 Dec 13 '21 at 13:25
  • 2
    Possible fix: remove the two `+=` lines completely, and replace `results.append(coordinate)` with `results.append((coordinate[0] + directions[x][0], coordinate[1] + directions[x][1]))` – Stef Dec 13 '21 at 13:27

4 Answers4

1

Okay, so that code does not do what you intend it to do. Lists are mutable which means that

>>> coordinate = [2, 3]
>>> oldCoordinate = coordinate
>>> coordinate.append(5)
>>> coordinate
[2, 3, 5]
>>> oldCoordinate  # oldCoordinate has changed too
[2, 3, 5]

an option would be to use copy

>>> coordinate = [2, 3]
>>> oldCoordinate = coordinate.copy()
>>> coordinate.append(5)
>>> coordinate
[2, 3, 5]
>>> oldCoordinate
[2, 3]

but even with that, there are things to change here cause your code is hard to reason about, it would be better to do that

def NeighborsFinder(coordinate, directions):
    newCoordinates = []
    for x, y in directions:
        newCoordinates.append([coordinate[0] + x, coordinate[1] + y])
    print(newCoordinates)

it's shorter, more beautiful and way easier to reason about

EDIT: But it can be even better actually, it can be a clear one liner

def neighbors_finder(coordinate, directions):
    return [[x + coordinate[0], y + coordinate[0]] for x, y in directions]
Arnaud PARAN
  • 126
  • 5
1

You are actually modifying the list which was passed into the function. For the minimal change to make this work, you need to create a .copy() when assigning the lists (otherwise it will just point the variable at the existing list):

def NeighborsFinder(coordinate):
    originalCoordinate = coordinate.copy()
    for x in range(0, len(directions)):
        coordinate[0] += directions[x][0]
        coordinate[1] += directions[x][1]
        results.append(coordinate)
        print(coordinate)
        coordinate = originalCoordinate.copy()
vaizki
  • 1,678
  • 1
  • 9
  • 12
1

In those two lines:

coordinate[0] += directions[x][0]

coordinate[1] += directions[x][1]

you have CHANGED the coordinates and the changes will RETAIN in the following steps.You don't want that.

You may create a copy of the original coordinate and compute the desired coordinates based on the copy, or so that in the next for loop, the coordinate is not changed. Or you can subtract the number added before in every loop.

Jim
  • 9
  • 2
0

It's because you are modifying coordinate. Let's modify your code:

def NeighborsFinder(coordinate):
    neighbors = []
    for x in range(0, len(directions)):
        neighbor = [coordinate[0] + directions[x][0], coordinate[1] + directions[x][1]]
        results.append(neighbor)
    return neighbors

# let's use the function
neighbors = NeighborsFinder([3, 5])
print(neighbors)

The other way to do it following your strategy:

results = []

def NeighborsFinder(coordinate):
    originalCoordinate = coordinate.copy()
    for x in range(0, len(directions)):
        coordinate = originalCoordinate.copy()
        coordinate[0] += directions[x][0]
        coordinate[1] += directions[x][1]
        results.append(coordinate)
        print(coordinate)

The best yet as per @Stef:

def NeighborsFinder(coordinate):
    neighbors = x,y = coordinate
    return [[x+dx, y+dy] for dx,dy in directions]
Tarik
  • 10,810
  • 2
  • 26
  • 40
  • Also with a list comprehension `x,y = coordinate; return [[x+dx, y+dy] for dx,dy in directions]` – Stef Dec 13 '21 at 13:31
  • @Stef yep, much better. You posted your comment before I could come to that :-) – Tarik Dec 13 '21 at 13:37