我有一个这样的列表:
[('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')]
对于更多相似的元组,这里的前两项只是顺序相反的IP地址。
现在,我需要创建一个在组合中唯一的新列表每个元组中的2个第一IP地址中的一个。
也就是说,就我的目的而言,('192.168.1.100', '192.168.1.101', 'A')
和('192.168.1.101', '192.168.1.100', 'A')
是一样的,我最终选择哪两个并不重要。尽管这些都不会与('192.168.1.101', '192.168.1.100', 'B')
相同
考虑到一开始的列表,我需要最终得到一个新的列表:
[('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')]
在python中,有什么优雅的方法可以做到这一点?
简单而低效的(O(n²)
)方法(谢谢,@RafałDowged!):
>>> 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')]
使用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')]
您可以根据最后一个元素进行排序:
>>> 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')]
>>> 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')])
一种可能的方法如下
>>> 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')]
>>>
假设差异是由于作为前两项的IP地址的顺序造成的,则创建一个生成器并将其提供给集合理解,以便元组中的IP地址始终按顺序排列。然后从集合中创建一个列表。
考虑到Rafel的评论,这里是另一个保留非重复元组顺序的解决方案
>>> 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)
我在上面的解决方案中使用一个集合来加快成员身份操作的原因
按标准化(即地址排序)值分组,返回原始值:
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()