I am creating a classical "set" class to practice, and the first thing I want to do is remove all duplicates. I know I could do it easily with dictionary keys, but I wanted to try to improve my list comprehension. These two functions should do the same thing, but the second doesn't work. Why?
for element in elements:
if elements.count(element) > 1:
self.elements = [elements.remove(element) for element in elements
if elements.count(element) > 1]
Don't iterate over and remove from the same list, you should also use a
Counter dict to count the occurrences of each element if your objects are hashable:
from collections import Counter cn = Counter(elements) # elements[:] changes original list elements[:] = (ele for ele in elements if ch[ele] < 2)
In your second code because
list.remove is an inplace operation it will just add
None's to your list anytime
if elements.count(element) > 1 is
True or else do nothing so the two code examples are completely different.
The first code if it does work only works by chance. When you remove an element from your list what a pointer was pointing to previously can change so you end up removing the wrong elements from your list.
An example of what your second code is doing and why your first is the wrong approach:
In : l = [2,3,1,4,1,5] In : l = [l.remove(i) if i > 1 else i for i in l] In : l Out: [None, 1, None, None]
Because you have changed the pointer values you end up removing the second
1 and with a few None's added because like all functions that operate inplace or don't specify a return value in python they return None by default.
If you actually want to get a unique set of all elements and not just keep the unique elements which is what your code seems to be attempting and also maintain the order, a
collections.OrderedDict dict will do what you need:
from collections import OrderedDict elements[:] = collections.OrderedDict.fromkeys(elements)