Home > Mobile >  Iterating over a 2D list while modifying the contents in Python
Iterating over a 2D list while modifying the contents in Python

Time:04-12

I'm writing a function for a project I'm working on that is supposed to take a 2D list of objects and edit them. I'm using a nested for loop, like so

class Thing:
    def __init__(self, x = 0, y = 0, sound = '...'):
        self.x = x
        self.y = y
        self.sound = sound

def change_list(to_change):
    for i in range(len(to_change)):
        for j in range(len(to_change[i])):
            to_change[i][j] = Thing(i, j, "Meow")
    return to_change

mylist = [[Thing()] * 1000] * 800
mylist = change_list(mylist)
print(mylist[1][1].x)
print(mylist[1][0].y)

I would expect the above code to output 1, however, it outputs 799. The code seems to work fine for assigning the y value. Could anybody help me out?

Thanks!

CodePudding user response:

This probably doesn't do what you think it does:

mylist = [[Thing()] * 1000] * 800

It creates a single Thing(), puts it in a list, then combines it into a list that has the same thing in it 1000 times. Then it takes that list, and creates another list that has the first list in it 800 times.

After all that - there's still only 1 actual Thing. Try this:

mylist = [[Thing()] * 2] * 2
mylist[0][0].x = 42
print(mylist[0][1], mylist[1][0], mylist[1][1])  # 42 42 42

If you wanted 800 lists of a 1000 things each, all 800,000 things separate things, you would do this:

mylist = [[Thing() for _ in range(1000)] for _ in range(800)]

This creates the thing a 1000 times in 800 separate lists each. However, none of it really matters because when calling change_list, you're replacing all of the former things with new things. Or at least, you would be if you'd created it the way describe in the previous example.

If that's what you're doing, you may as well generated the whole list anew:

def create_list(rows, cols):
    return [[Thing(col, row) for row in range(rows)] for col in range(cols)]

If you just want to change what's already there (for example just updating the x and y of existing things:

def change_list(to_change):
    for ncol, col in enumerate(to_change):
        for nrow, thing in enumerate(col):
            thing.x = ncol
            thing.y = nrow
            thing.sound = 'Meow'

You don't need to access the length, you can just loop over the contents of something and use enumerate() if you need the relative position (index) of the thing as well.

  • Related