删除元组的元组中的重复项

2024-05-23 17:46:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我有以下元组:

# my Noah's Ark    
myanimals = (('cat', 'dog'), ('callitrix', 'platypus'), ('anaconda', 'python'), ('mouse', 'girafe'),   ... ,('platypus', 'callitrix'))

因为我想要一个2元组动物的独特列表,所以这对(‘鸭嘴兽’、‘鸭嘴兽’)被认为是(‘鸭嘴兽’、‘鸭嘴兽’)的复制品

我怎样才能优雅地从我的动物身上(用最少的代码)移除(a,b)的所有类型的对(b,a)副本


Tags: 列表myanacondacat元组动物arkdog
2条回答

您可以对排序的元组值使用集合,或者将列表转换为字典,其中键是按排序顺序排列的元组。这将为每个组合只留下一个值:

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函数通过将关键部分与原始元组相结合来实现这一点:

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

我将分两部分回答:

  1. 严格来说,这不是对您的问题的回答,而是一个建议,它可以让您更轻松地处理这个问题:如果您的代码允许使用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'}

  1. 实际上,使用元组有点麻烦。由于元组是不可变的,因此您需要从头开始创建一个新元组,并在此过程中过滤掉重复的元组:
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) )

相关问题 更多 >