Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

filter out "reversed" duplicated tuples from a list in Python

Tags:

python

I've a list like this:

[('192.168.1.100', '192.168.1.101', 'A'), ('192.168.1.101', '192.168.1.100', 'A'), 
 ('192.168.1.103', '192.168.1.101', 'B'), ('192.168.1.104', '192.168.1.100', 'C')]

And with many more similar tuples, here the two first items are just the IP addresses in the opposite order.

Now, I need to create a new list which is unique on the combination of the 2 first IP addresses in each tuple.

That is, for my purpose ('192.168.1.100', '192.168.1.101', 'A') is the same as ('192.168.1.101', '192.168.1.100', 'A') , it doesn't matter which of those 2 I end up with. Though none of those would be the same as ('192.168.1.101', '192.168.1.100', 'B')

Given the list at the start, I need to end up with a new list:

    [('192.168.1.101', '192.168.1.100', 'A'), ('192.168.1.103', '192.168.1.101', 'B'), 
     ('192.168.1.104', '192.168.1.100', 'A')]

What's an elegant way of doing this in python ?

like image 287
user1255770 Avatar asked Feb 22 '23 00:02

user1255770


1 Answers

The straightforward, yet inefficient (O(n²)) approach (thanks, @Rafał Dowgird!):

>>> uniq=[]
>>> for i in l:                           # O(n), n being the size of l
...     if not (i in uniq or tuple([i[1], i[0], i[2]]) in uniq): # O(n)
...             uniq.append(i)                                   # O(1)
... 
>>> uniq
[('192.168.1.100', '192.168.1.101', 'A'), 
 ('192.168.1.103', '192.168.1.101', 'B'), 
 ('192.168.1.104', '192.168.1.100', 'C')]

A more efficient approach using Python's Set:

>>> uniq=set()
>>> for i in l: # O(n), n=|l|
...     if not (i in uniq or tuple([i[1], i[0], i[2]]) in uniq): # O(1)-Hashtable
...             uniq.add(i)
... 
>>> list(uniq)
[('192.168.1.104', '192.168.1.100', 'C'), 
 ('192.168.1.100', '192.168.1.101', 'A'), 
 ('192.168.1.103', '192.168.1.101', 'B')]

You can sort it according to the last element:

>>> sorted(list(uniq), key=lambda i:i[2])
[('192.168.1.100', '192.168.1.101', 'A'), 
 ('192.168.1.103', '192.168.1.101', 'B'), 
 ('192.168.1.104', '192.168.1.100', 'C')]
like image 139
Adam Matan Avatar answered Mar 24 '23 14:03

Adam Matan