【发布时间】:2013-04-12 00:33:38
【问题描述】:
假设我有一个看起来像这样的列表:
a = [(1,2),(3,1),(2,1),(4,5),(9,3),(1,3)]
然后,我想要一些看起来像这样的东西:
b = [(1,2),(3,1),(4,5),(9,3)]
非常感谢!
【问题讨论】:
标签: 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)]
非常感谢!
【问题讨论】:
标签: python tuples list-comprehension
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)))]
【讨论】:
修改@Pavel 的解决方案,使用frozenset 使其更高效,因为它避免了排序并且通常在原始速度上更快。这应该是O(nm),而@Pavel 应该是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)
您可以添加更多调整以使这些更快,例如使用列表推导式,但这很快就会变得丑陋。可以与最后一种结合使用的另一种常见技术是:
seen_add, b_append = seen.add, b.append # speeds up name lookup
从那时起可以直接调用这些,但请记住,过早的优化是邪恶的。
【讨论】:
只要把你的清单,做成一个集合,然后再把它变成一个清单
>>>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)]
【讨论】:
在 Python 3.7+(即字典维护插入顺序的版本)中,您可以简单地将列表转换为以元组的 freezesets 为键的字典并获取其值:
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)]
【讨论】: