What is most efficieny way of updating a table with removing the old content from the memory?

Viewed 39

I have the following code:

class MyClass:

    def __init__(self):
        self.w = 2
        self.h = 2
        self.table = []

    def add_item(self, x, y, string_value):

        table0 = self.table
        if x >= self.w:
            self.w = x + 1
        if y >= self.h:
            self.h = y + 1

        self.table = [['foo' for h in range(self.h)] for w in range(self.w)]
        for i in range(0, len(table0)):
            for j in range(0, len(table0[i])):
                self.table[i][j] = table0[i][j]

        self.table[x][y] = string_value


def main():
    c = MyClass()
    c.add_item(7, 0, 'May')
    c.add_item(0, 5, 'June')
    c.add_item(2, 3, 'January')


if __name__ == "__main__":
    main()

This code takes the coordinates from the user to add a cell with a specific value to the table. To do so, if the coordinates are greater than the current table's dimension, then table's dimension will be updated accordingly. I have two questions:

  1. There is a nested loop in the add_item function to copy the previous content into the updated table. In terms of time complexity, isn't there a more efficient way to do that?
  2. Each time when the table is updated, the previous content is still in the memory without being assigned to any variable, so how do I get rid of it? I know there is Garbage Collector interface in python, but I never used it before, if this is the correct way, how do I use it?

Thanks.

2 Answers

It would be better to not recreate the list each time. Look at this version : only the needed cells are created dynamically while existing one are kept :

class MyClass:

    def __init__(self):
        self.w = 0
        self.h = 0
        self.table = []

    def add_item(self, x, y, string_value):

        while y >= self.h:
            for xx in range(self.w):
                self.table[xx].append(None)
            self.h = self.h + 1
          
        while x >= self.w:
            self.table.append([None] * self.h)
            self.w = self.w + 1
        
        self.table[x][y] = string_value


def main():
    c = MyClass()
    c.add_item(7, 0, 'May')
    c.add_item(0, 5, 'June')
    c.add_item(2, 3, 'January')
    print(c.table) #=>[[None, None, None, None, None, 'June'], [None, None, None, None, None, None], [None, None, None, 'January', None, None], [None, None, None, None, None, None], [None, None, None, None, None, None], [None, None, None, None, None, None], [None, None, None, None, None, None], ['May', None, None, None, None, None]]

if __name__ == "__main__":
    main()

Note also that a garbage collector is something doing its job automatically. Normally you don't have to worry about it.

Modifying the existing list might be the better option.

def add_item(self, x, y, string_value, default_value=None):
    self.w = max(self.w, x)
    while len(self.table) <= self.w:
        self.table.append([])
    self.h = max(self.h, y)
    for line in self.table:
        while len(line) <= self.h:
            line.append(default_value)
    self.table[x][y] = string_value

Concerning the question about the garbage collector: Your data will be thrown away as soon as it is no longer referenced. The garbage collector is the last resort and can detect cyclic references of unused objects. When I started with Python I thought I would have to handle that memory management manually. In fact I never needed the gc module in over 15 years.

Related