[英]Remove duplicates in a tuple of tuples
我有以下元组元组:
# my Noah's Ark
myanimals = (('cat', 'dog'), ('callitrix', 'platypus'), ('anaconda', 'python'), ('mouse', 'girafe'), ... ,('platypus', 'callitrix'))
由于我想要一个唯一的 2 元组动物列表,因此这对 ('platypus', 'callitrix') 被认为是 ('callitrix', 'platypus') 的副本。
我怎样才能优雅地从我的动物(用最少的代码)中删除(a,b)的所有类型的对(b,a)重复?
我分两部分回答:
set
而不是tuple
,您可以使用关键字in
来检查您需要的内容:myanimals = ({'cat', 'dog'}, {'callitrix', 'platypus'}, {'anaconda', 'python'}, {'mouse', 'girafe'}, ... {('platypus', 'callitrix')})
{'platypus', 'callitrix'} in myanimals # returns True, since {'a', 'b'}=={'b', 'a'}
因此,制作一组集合将使重复项被自动删除:
myanimals = {{'cat', 'dog'}, {'callitrix', 'platypus'}, {'anaconda', 'python'}, {'mouse', 'girafe'}, ..., {'platypus', 'callitrix'} }
将自动删除重复的{'platypus', 'callitrix'}
。
然而,这样做意味着你不能让成对的动物成为相同的两个动物,因为{'a', 'a'}
只是{'a'}
。
myanimals = (('cat', 'dog'), ('callitrix', 'platypus'), ('anaconda', 'python'), ('mouse', 'girafe'), ... ,('platypus', 'callitrix'))
myanimals_clean = []
for pair in myanimals:
if pair not in myanimals_clean and (pair[1], pair[0]) not in myanimal_clean:
myanimals_clean.append(pair)
您可以使用itertools.permutations()
稍微清理一下,但我认为额外导入的麻烦不值得。
最后,您可以混合使用这两个答案,并将您的元组元组转换为集合元组以进行检查,然后再返回元组:
myanimals = tuple( (set(pair) for pair in myanimals) )
myanimals = tuple( (tuple(pair) for pair in myanimals if pair not in myanimals) )
您可以在已排序的元组值上使用集合,或将列表转换为字典,其中键是按排序顺序的元组。 这将只留下每个组合一个值:
list({*map(tuple,map(sorted,myanimals))})
或者
list(dict(zip(map(tuple,map(sorted,myanimals)),myanimals)).values())
坏掉了
[*map(sorted,myanimals)] # sorted tuples
# [['cat', 'dog'], ['callitrix', 'platypus'], ['anaconda', 'python'], ['girafe', 'mouse'], ['callitrix', 'platypus']]
# notice that both ('callitrix', 'platypus') and ('platypus', 'callitrix')
# are converted to ('callitrix', 'platypus')
由于这给出了一个列表列表,并且字典键需要是可散列的,我们将项目转换为元组:
[*map(tuple,map(sorted,myanimals))]
# [('cat', 'dog'), ('callitrix', 'platypus'), ('anaconda', 'python'), ('girafe', 'mouse'), ('callitrix', 'platypus')]
通过将它们放在一个集合中并将集合转换回列表,这些已经可以转换为唯一对的列表:
list({*map(tuple,map(sorted,myanimals))})
# [('girafe', 'mouse'), ('callitrix', 'platypus'), ('anaconda', 'python'), ('cat', 'dog')]
如果您不关心每个元组中值的原始顺序,则可以停止。 但是,如果您需要 ('mouse','girafe') 保持该顺序,那么我们需要一个额外的步骤来将唯一性过滤与元组内容分开。 这就是字典的用武之地。我们希望将这些排序的元组用作键,但保留原始顺序作为值。 zip function 通过将关键部分与原始元组组合来实现这一点:
[*zip(map(tuple,map(sorted,myanimals)),myanimals)]
# [(('cat', 'dog'), ('cat', 'dog')), (('callitrix', 'platypus'), ('callitrix', 'platypus')), (('anaconda', 'python'), ('anaconda', 'python')), (('girafe', 'mouse'), ('mouse', 'girafe')), (('callitrix', 'platypus'), ('platypus', 'callitrix'))]
将其输入字典只会保留每个不同键的最后一个值,我们可以简单地选取这些值来形成元组的结果列表:
list(dict(zip(map(tuple,map(sorted,myanimals)),myanimals)).values())
[('cat', 'dog'), ('platypus', 'callitrix'), ('anaconda', 'python'), ('mouse', 'girafe')]
或者
请注意,上面选择的 ('platypus', 'callitrix') 优于 ('platypus', 'callitrix') 因为它保留了最后一次出现的重复条目。
如果您需要保留第一次出现,您可以使用不同的方法,根据每个元组第一次添加到集合中逐步填充一组元组顺序和过滤器。
[t for s in [{myanimals}] for t in myanimals
if t not in s and not s.update((t,t[::-1]))]
# [('cat', 'dog'), ('callitrix', 'platypus'), ('anaconda', 'python'), ('mouse', 'girafe')]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.