【问题标题】:Remove duplicates in a tuple of tuples删除元组元组中的重复项
【发布时间】:2021-01-20 05:23:36
【问题描述】:

我有以下元组:

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

由于我想要一个唯一的 2 元组动物列表,因此 ('platypus', 'callitrix') 对被认为是 ('callitrix', 'platypus') 的副本。

我怎样才能优雅地从 myanimals 中删除(使用最少的代码)所有类型的 (b,a) 对 (a, b) 重复项?

【问题讨论】:

标签: python duplicates tuples namedtuple


【解决方案1】:

我将分两部分回答:

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

【讨论】:

    【解决方案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')]
    

    【讨论】:

      猜你喜欢
      • 2019-03-07
      • 2019-03-29
      • 2021-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-23
      • 1970-01-01
      相关资源
      最近更新 更多