2012-03-29 8 views
1

Ich habe eine Liste wie folgt aus:Filter out „umgekehrt“ duplizierte Tupel aus einer Liste in Python

[('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')] 

Und mit vielen weiteren ähnlichen Tupeln, hier die beiden ersten Punkte sind nur die IP-Adressen in die entgegengesetzte Auftrag.

Jetzt muss ich eine neue Liste erstellen, die auf der Kombination der ersten beiden IP-Adressen in jedem Tupel eindeutig ist.

Das ist, für meinen Zweck ('192.168.1.100', '192.168.1.101', 'A') ist das gleiche wie ('192.168.1.101', '192.168.1.100', 'A'), es ist egal, welche dieser 2 ich am Ende mit. Obwohl keiner von denen, wäre die gleich wie ('192.168.1.101', '192.168.1.100', 'B')

die Liste am Anfang gegeben, ich brauche eine neue Liste am Ende:

[('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')] 

Was ist ein eleganter Weg, dies in Python zu tun?

+0

Siehe meinen Kommentar unter Abhijits Lösung. Ist es wichtig, wenn '('192.168.9.1', '192.168.1.1', 'B') in' ('192.168.1.1', '192.168.9.1', 'B') umgewandelt wird, auch wenn die zweite Form tritt in der Eingabe überhaupt nicht auf? –

+0

Ich denke, Sie haben einen Tippfehler. '('192.168.1.104', '192.168.1.100', 'A')' sollte '('192.168.1.104', '192.168.1.100', 'C')' auf der vorletzten Zeile sein. –

+0

@ Rafał Dowgird Nr. – user1255770

Antwort

2

Die einfache, aber ineffizient (O(n²)) Ansatz (Danke, @ 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')] 

Ein effizienterer Ansatz mit Python 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')] 

Sie können sortieren nach das letzte 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')] 
+0

Ouch, dies hat aufgrund des linearen Tests O (n^2) -Komplexität für die Mitgliedschaft in der "uniq" -Liste. –

+0

Richtig, aber es ist klar und der Unterschied ist für kurze Listen gering. Ich werde es mit Sets, wie auch immer, überarbeiten. –

1

Ein möglicher Weg zu d o dies wäre als

>>> somelist=[('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')] 
>>> list(set((y,x,z) if x > y else (x,y,z) for (x,y,z) in somelist)) 
[('192.168.1.100', '192.168.1.104', 'C'), ('192.168.1.100', '192.168.1.101', 'A'), ('192.168.1.101', '192.168.1.103', 'B')] 
>>> 

folgt Unter der Annahme, der Unterschied aufgrund der Reihenfolge der IP-Adressen, die die ersten beiden Artikel sind, einen Generator erstellen und ihn so zu einem Satz Verständnis, dass die IP-Adresse in den Tupeln sind immer in Ordnung. Dann erstellen Sie eine Liste aus dem Set.

hier Rafel Kommentar In Anbetracht ist eine andere Lösung, die den Auftrag eines nicht doppelte Tupel

>>> someset=set() 
>>> [someset.add(e) for e in somelist if (e not in someset and e[0:2][::-1]+e[2:] not in someset)] 
>>> list(someset) 

Der Grund, warum ich bin mit einem Satz in der obigen Lösung bewahrt die Mitgliedschaft Betrieb schneller

+0

Ein Vorbehalt: OP stellte nur fest, dass es keine Rolle spielt, welches der beiden äquivalenten Tupel im Ergebnis landen wird, wenn es tatsächlich 2 äquivalente Tupel gibt. Diese Lösung konvertiert möglicherweise ein Tupel in seine äquivalente Form, auch wenn das andere Formular nicht in der Eingabe vorkommt. –

+0

@ RafałDowgird: Siehe mein Update – Abhijit

2
>>> L=[('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')] 
>>> set(tuple(sorted((a,b))+[c]) for a,b,c in L) 
set([('192.168.1.100', '192.168.1.104', 'C'), ('192.168.1.100', '192.168.1.101', 'A'), ('192.168.1.101', '192.168.1.103', 'B')]) 
zu machen
+0

Und Sie können das Ganze in 'list()' verpacken, um eine Liste zu erhalten. –

+0

+1 Ich mag deine Lösung - Pythonic und elegant. –

1

Gruppe von normalisierten (dh Adressen sortiert) Werte, Rück ursprünglichen:

data = [('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')] 
normalized = dict([(min(t[0], t[1]), max(t[0], t[1]), t[2]), t] 
        for t in data) 
result = normalized.values() 
Verwandte Themen