在列表中查找唯一元组(忽略顺序),同时在python中保留其他元组的原始顺序?

时间:2013-04-12 00:33:38

标签: python tuples list-comprehension

说我的列表看起来像这样:

a = [(1,2),(3,1),(2,1),(4,5),(9,3),(1,3)]

然后,我希望看到这样的东西:

b = [(1,2),(3,1),(4,5),(9,3)]

非常感谢!

4 个答案:

答案 0 :(得分:4)

b = []
seen = set()
for t in a:
    s = tuple(sorted(t))
    if s not in seen:
        seen.add(s)
        b.append(t)

seen = set()
b = [t for t in a if tuple(sorted(t)) not in seen and not seen.add(tuple(sorted(t)))]

答案 1 :(得分:3)

修改@Pavel的解决方案,该解决方案使用frozenset使其更有效,因为它避免了排序,并且通常更快地提高原始速度。这应该是O(nm)与@ Pavel的比较{@ 1}},其中O(n * m log(m))是列表的长度,n是每个元组的长度。

m

以下是差异的证明:

>>> a = [(1,2),(3,1),(2,1),(4,5),(9,3),(1,3)]
>>> b = []
>>> seen = set()
>>> for t in a:
        s = frozenset(t)
        if s not in seen:
            seen.add(s)
            b.append(t)


>>> b
[(1, 2), (3, 1), (4, 5), (9, 3)]

from timeit import timeit


def dosorted(a):
    b = []
    seen = set()
    for t in a:
        s = tuple(sorted(t))
        if s not in seen:
            seen.add(s)
            b.append(t)
    return b

def dofrozenset(a):
    b = []
    seen = set()
    for t in a:
        s = frozenset(t)
        if s not in seen:
            seen.add(s)
            b.append(t)
    return b

import random
a = [(1,2),(3,1),(2,1),(4,5),(9,3),(1,3)]
b = [tuple(random.randrange(3) for x in range(10)) for x in range(10)]
c = [tuple(random.randrange(3) for x in range(20)) for x in range(20)]

setup = '''
from __main__ import a, b, c, dosorted, dofrozenset'''

print timeit(setup=setup, stmt='dosorted(a)')
print timeit(setup=setup, stmt='dosorted(b)')
print timeit(setup=setup, stmt='dosorted(c)')
print timeit(setup=setup, stmt='dofrozenset(a)')
print timeit(setup=setup, stmt='dofrozenset(b)')
print timeit(setup=setup, stmt='dofrozenset(c)')

你可以添加一些更多的调整来使这些更快,例如使用列表理解,但这很快就会变得难看。可以与最后一个一起使用的另一种常见技术是:

9.23814695723 # dosorted(a)
26.8939069072 # dosorted(b)
86.6305864991 # dosorted(c)

5.99305211975 # dofrozenset(a)
10.708619182  # dofrozenset(b)
25.5252673175 # dofrozenset(c)

然后可以直接调用这些,但请记住,过早优化是邪恶的。

答案 2 :(得分:1)

只需获取您的列表,将其设置为一个集合,然后将其转回列表

>>>a = [(1, 2), (3, 1), (2, 1), (4, 5), (9, 3), (1, 3)]
>>>sorted_tuples = [tuple(sorted(tuple_)) for tuple_ in a]
>>>list(set(sorted_tuples))
[(1, 2), (4, 5), (3, 9), (1, 3)]

答案 3 :(得分:0)

在Python 3.7+中(即字典维护插入顺序的版本),您只需将列表转换为以元组的冻结集为键的字典并获取其值:

a = [(1,2), (3,1), (2,1), (4,5), (9,3), (1,3)]
d = {}

for x in a:
    d.setdefault(frozenset(x), x)

print(list(d.values()))  # [(1, 2), (3, 1), (4, 5), (9, 3)]