Search code examples
pythonfunctionvariablesnonetype

.remove() is removing elements from both variables (lists) (which I set equal to each other) when I only want to remove it from one variable


I have a list called ranks and a list called modelRanks, they are equal. When I iterate through my for loop I want to remove anything from modelRanks that has a count of 2 or more in ranks. I used the remove function and it is removing the element from both when I call it to only remove from modelRanks.

I've also tried modelRanks = modelRanks.remove(num) and modelRanks -= [num]

This is my code currently. I am using python 3.7.

def modelForPairs(ranks):

    modelRanks = ranks

    for num in ranks:
        count = ranks.count(num)

        if count > 1:
            modelRanks.remove(num)

    return modelRanks

If my list of ranks is [11, 2, 3, 11, 3], I want my modelRanks to end up looking like [2]. If ranks = [2, 4, 3, 11, 3] I want modelRanks to end up looking like [2, 4, 11] and etc.


Solution

  • In your code, just change the line modelRanks = ranks to modelRanks = ranks.copy().

    In Python, setting a variable equal to a list just points it to that list object; it does not create a copy by default. For example:

    lst = [1, 2, 3]
    lst2 = lst
    lst2.remove(2)
    print(lst2)
    # [1, 3]
    print(lst)
    # [1, 3]
    # They're the same object!
    

    You can get around this by explicitly calling lst.copy() or lst[:] (see the docs). Both of these perform what's called a shallow copy.

    lst = [1, 2, 3]
    lst2 = lst.copy()  # or lst2 = lst[:]
    lst2.remove(2)
    print(lst2)
    # [1, 3]
    print(lst)
    # [1, 2, 3]
    # Different objects!
    

    A note on shallow vs. deep copies (because I see a lot of evidence that there is some confusion on this point). From the docs:

    The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

    • A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.

    • A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

    Basically if your list contains other objects, and you explicitly need to avoid just pointing to the same objects in the new list, then and only then do you need to use a deep copy. A shallow copy will populate a new list with pointers to the same objects. Removing items from this list will not affect the original objects in any way, and will only remove them from the new list.

    A deep copy will create entirely new objects, recursively, for everything in your list. This is often unnecessary, but it's good to be aware of the distinction for cases where you, for instance, want to copy items into a new list and manipulate only those items in the new list, not the original items from where they were copied.

    If none of that made sense to you, don't worry about it. You may run into some headaches in the future with copying lists, in which case remember to look in to deep vs. shallow copies.