您可以对已排序的元组值使用集合,或者将列表转换为字典,其中键是按排序顺序的元组。这样每个组合只会留下一个值:
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')]