Home > front end >  Iterate through a list writing to all previous indices
Iterate through a list writing to all previous indices

Time:04-17

I'm trying to create a list that holds the coordinates of an object.

crds = [0,0,0]
class create:
   line = [["!PlacementError!"] for i in range(0, 8)]
   def lineIterate():
       for i in range(0, len(create.line)):
           print(i)
           crds[0] = i   0
           print(create.line)
           create.line[i] = crds
           print(create.line)
           print(create.line[i])

When I run the code it writes to each index but also all previous indices.

0 [[0, 0, 0], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!']]

1 [[1, 0, 0], [1, 0, 0], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!'], ['!PlacementError!']]

What is should be: [[0, 0, 0],[1, 0, 0]]

CodePudding user response:

In your code there is only one crds list, which you mutate and repeatedly reference in the line array. But since it is only one list, when you mutate it, you actually mutate the list that you already assigned to line[i] in a previous iteration.

The solution is to create a new list in each iteration, so that line will get references to separate lists, not the same one. For instance, you could create a copy on each assignment to line[i]:

create.line[i] = crds[:]

CodePudding user response:

It's seems that you put crds = [0,0,0] in line[0], and then you changed the crds from [0,0,0] to [1,0,0], and you put the new(actually not) crds to line[1].

you may think that the line should be like: [[0,0,0], [1,0,0]]. Python uses the Shallow Copy, so when you let an element of line equal to crds, python just created a link from the element to crds, your line is actually: [crds, crds, crds...], when you change element in crds, all the element in line will be changed. by using id() function you can get the id of the object in python.

print('        id of crds:', id(crds))
print('element id in line:',list(map(id,  create.line)))

        id of crds: 2349824066880
element id in line: [2349824066880, 2349824066880, 2349824066880, 2349824066880, 2349824066880, 2349824066880, 2349824066880, 2349824066880]

this may be what you want:

class Creat(object):
    """docstring for Creat"""
    def __init__(self):
        super(Creat, self).__init__()
        self.line = [["!PlacementError!"]]*8

    def lineIterate(self):
        for i in range (0, len(self.line)):
            self.line[i] = [i, 0, 0]
        print(self.line)
        
if __name__ == '__main__':
    c = Creat()
    c.lineIterate()

>>> [[0, 0, 0], [1, 0, 0], [2, 0, 0], [3, 0, 0], [4, 0, 0], [5, 0, 0], [6, 0, 0], [7, 0, 0]]

or you can use deepcopy or line[i] = crds[:]:

import copy
class Creat(object):
    """docstring for Creat"""
    def __init__(self):
        super(Creat, self).__init__()
        self.line = [["!PlacementError!"]]*8
        self.crds = [0, 0, 0]

    def lineIterate(self):
        for i in range (0, len(self.line)):
            self.crds[0] = i   0
            self.line[i] = copy.deepcopy(self.crds)
            self.line[i] = crds[:]             # the same as deepcopy
        print(self.line)

if __name__ == '__main__':
    c = Creat()
    c.lineIterate()

>>> [[0, 0, 0], [1, 0, 0], [2, 0, 0], [3, 0, 0], [4, 0, 0], [5, 0, 0], [6, 0, 0], [7, 0, 0]]

Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other. Shallow and deep copy operations

  • Related