How to make a Python list based on another list

Viewed 101

I have a master list and then a whole bunch (100s) of sublists cherry-picked from the master list. However, over time items in the master list will be removed. I want to also remove those items from each of the sublists. I imagine having a list that is only pointers to the master list. As the pointer goes stale then the list gets smaller. The sublists are normally in objects not easily accessible at the point where the master list is edited. Is this possible?

master = ["first","last","middle","top","bottom","left","right","inside"]

sides = []
sides.append(master[2])
sides.append(master[3])
sides.append(master[4])

centre = []
centre.append(master[0])
centre.append(master[2])
centre.append(master[7])

print(master)
['first', 'last', 'middle', 'top', 'bottom', 'left', 'right', 'inside']
print(sides)
['middle', 'top', 'bottom']
print(centre)
['first', 'middle', 'inside']

master.remove("middle")

print(master)
['first', 'last', 'top', 'bottom', 'left', 'right', 'inside']
print(sides) # Ideal outcome
['top', 'bottom']
print(centre) # Ideal outcome
['first', 'inside']
4 Answers

You could use a custom class that subclasses list. This way you can tailor the behavior of .remove:

class Lists(list):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # logic here, for now using the whole passed list
        self.sides = self[:]
        self.center = self[:]

    def remove(self, obj):
        #  TODO catch ValueError that is raised if obj isn't in all of the lists
        super().remove(obj)
        self.sides.remove(obj)
        self.center.remove(obj)

   # probably overriding other methods from list, such as append, so 
   # an instance can be used directly to interact with the "master" list

my_lists = Lists(["first", "last", "middle", "top", "bottom", "left", "right", "inside"])

print(my_lists)
my_lists.remove('last')
print(my_lists)
print(my_lists.sides)
print(my_lists.center)

# ['first', 'last', 'middle', 'top', 'bottom', 'left', 'right', 'inside']
# ['first', 'middle', 'top', 'bottom', 'left', 'right', 'inside']
# ['first', 'middle', 'top', 'bottom', 'left', 'right', 'inside']
# ['first', 'middle', 'top', 'bottom', 'left', 'right', 'inside']

You could also better encapsulate .master if needed (as the in-code comment suggests).


However, you may want to rethink the problem and the approach you have chosen to solve it. There might be a better way than keeping sublists of the original list, and you should also keep in mind that .remove will raise an exception if you try to delete a non-existing element from the list.

The list element needs to be removed for every list that it is in. All you need to do to implement this is -

print(master)
['first', 'last', 'middle', 'top', 'bottom', 'left', 'right', 'inside']
print(sides)
['middle', 'top', 'bottom']
print(centre)
['first', 'middle', 'inside']

master.remove("middle")
sides.remove("middle")
centre.remove("middle")

print(master)
['first', 'last', 'top', 'bottom', 'left', 'right', 'inside']
print(sides) # Ideal outcome
['top', 'bottom']
print(centre) # Ideal outcome
['first', 'inside']

I came up with a solution for your problem, but it doesn't answer your question since I didn't link the different lists.

Nevertheless, I propose you this function:

def del_item(item, *args) :
    for lst in args :
        if item in lst :
            lst.remove(item)

Then you just have to call this function with the item you want to pop out and the different lists that you want to check.

Hope this can be useful

As modifying lists wasn't possible programatically without an iterative step I think the problem is better answered using a database query rather than a list data structure. Thanks @DeepSpace for a good answer

Related