Removing opposite lists from list of lists

Viewed 49

I need to remove from a list of lists all the opposite couples of lists. For example, if my list of lists is l = [[1], [-1], [-1], [2], [2], [2], [-2]], and I need to remove the couple of opposite lists, the output should be l_out = [[-1], [2], [2]], because I remove a [1], [-1] and a [2], [-2]. How can I do this procedure recursively with a loop?

3 Answers
from collections import Counter


l = [[1], [-1], [-1], [2], [2], [2], [-2]]

c = Counter(v for (v, ) in l)
out = [[v] for v in c for _ in range(c.get(v, 0)-c.get(-v, 0))]

print(out)

Prints;

[[-1], [2], [2]]

So, to do this efficiently, you can keep track of the opposite in a dict along with the index it was encountered. When building up the resulting list, use None to mark spots that need to be deleted, and just do a second pass to filter out nones, making keeping track of the indices much easier:

In [1]: data  = [[1], [-1], [-1], [2], [2], [2], [-2]]

In [2]: seen = {}

In [3]: result = []
   ...: default = 0, None
   ...: for i, (x,) in enumerate(data): # again, why single lists?
   ...:     n, j = seen.get(-x, default)
   ...:     if n == 0:
   ...:         seen[-x] = 1, i
   ...:         result.append([x])
   ...:     elif n == 1:
   ...:         seen[-x] = 0, i
   ...:         result.append(None)
   ...:         result[j] = None
   ...:

In [4]: result
Out[4]: [[1], None, None, None, None, [2], [-2]]

In [5]: [x for x in result if x is not None]
Out[5]: [[1], [2], [-2]]

So, this is still linear time, albeit, using auxiliary, linear space.

You could pop from the back as well.

l = [[1], [-1], [-1], [2], [2], [2], [-2]]
i = len(l)-1
if i%2==0:
    i=i-1
while i>0:
    l.pop(i)
    i-=2
    
print(l)
Related