从Python中的列表中筛选出“反向”重复的元组

时间:2012-03-29 09:08:01

标签: 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')]

对于更多类似的元组,这里的两个第一项只是相反顺序的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中执行此操作的优雅方法是什么?

4 个答案:

答案 0 :(得分:2)

直截了当但效率低下(O(n²))的方法(谢谢,@RafałFowgird!):

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

答案 1 :(得分: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')])

答案 2 :(得分:1)

一种可行的方法如下

>>> 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)

我在上述解决方案中使用集合以使会员操作更快的原因

答案 3 :(得分:1)

按归一​​化(即地址排序)值分组,返回原始值:

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()