获取Python列表中唯一的元组,不考虑顺序。

20

我有一个Python列表:

[ (2,2),(2,3),(1,4),(2,2), etc...]
我需要的是某种将其减少到唯一组件的函数......在上面的列表中,这将是:
[ (2,2),(2,3),(1,4) ]

numpy的unique函数并不能完全做到这一点。我可以想到一种方法来实现-将我的元组转换为数字[22,23,14,etc.],找到唯一值,然后从那里开始处理...但我不知道复杂性是否会失控。有没有一个函数可以像我试图使用元组做的那样呢?


这是一个演示问题的代码示例:

 import numpy as np

 x = [(2,2),(2,2),(2,3)]
 y = np.unique(x)

返回值: y: [2 3]

以下是修复后的解决方案实现:

 x = [(2,2),(2,2),(2,3)]
 y = list(set(x))
返回结果为:y 的值为 [(2,2),(2,3)]。

1
顺序重要吗? - zondo
2
无论你如何“找到数字的独特之处”,只需尝试使用元组。你认为这会有什么不同吗? - jonrsharpe
1
@jonrsharpe,使用numpy在元组上运行它,但没有成功。 - Chris
1
那么,为什么您没有提供代码的 [mcve] 和比“没有工作”更具体的问题描述呢? - jonrsharpe
@jonrsharpe,看了你提供的链接,我引用一下里面的话:“当询问一个由你的代码引起的问题时,如果你提供可用于重现问题的代码,你将得到更好的答案。那段代码应该是……”我在几分钟内得到了惊人的答案,而没有发布“最小、完整和可验证的示例”。根据文档,如果我对答案的质量感到满意,就没有问题。但我还是包含了它。 - Chris
1
你得到答案并不意味着这个问题的第一次修订变得更好了,也不意味着在你写下一个问题时你不能改进;请在未来展示你的工作过程。 - jonrsharpe
4个回答

36

如果顺序并不重要

如果结果的顺序不关键,你可以将列表转换为集合(因为元组是可哈希的),然后再将集合转换回列表:

>>> l = [(2,2),(2,3),(1,4),(2,2)]
>>> list(set(l))
[(2, 3), (1, 4), (2, 2)]

如果顺序很重要

(更新)

自CPython 3.6(或任何Python 3.7版本)开始,常规字典会记住它们的插入顺序,因此您可以简单地执行:

>>> l = [(2,2),(2,3),(1,4),(2,2)]
>>> list(dict.fromkeys(l))
[(2, 2), (2, 3), (1, 4)]
如果顺序很重要,过滤重复项的规范方法是这样的:

>>> seen = set()
>>> result = []
>>> for item in l:
...     if item not in seen:
...         seen.add(item)
...         result.append(item)
... 
>>> result
[(2, 2), (2, 3), (1, 4)]

最后,你可以稍微慢一点而且有点更像黑客的方法,滥用 OrderedDict 来作为有序集合:

>>> from collections import OrderedDict
>>> OrderedDict.fromkeys(l).keys() # or list(OrderedDict.fromkeys(l)) if using a version where keys() does not return a list
[(2, 2), (2, 3), (1, 4)]

12

使用set可以去除重复元素,然后你可以创建一个list

>>> list(set([ (2,2),(2,3),(1,4),(2,2) ]))
[(2, 3), (1, 4), (2, 2)]

12

你可以简单地做

y = np.unique(x, axis=0)
z = [] 
for i in y:
   z.append(tuple(i))

原因是numpy将元组列表解释为2D数组。通过设置axis=0,您要求numpy不要扁平化数组并返回唯一的行。


1
这会输出一个二维数组,给出你想要的内容。如果你想要一个元组列表,那么考虑我的答案的编辑版本。 - Mehdi Golari
1
我认为使用np.unique更符合我的预期。 - Chris
1
好的解决方案,可以使用列表推导式使其更短:[tuple(i) for i in np.unique(x, axis=0)] - Bert Coerver
如果我们的原始列表是这样的呢?[(1, [[3, 3, 3], 3, 3]), (2, [[4, 4, 4], 4, 4]), (3, [[5, 5, 5], 5, 5]), (1, [[3, 3, 3], 3, 3])] - Ash

6

set()函数将去除所有重复元素,然后您可以将其转换回列表:

unique = list(set(mylist))

使用set()会破坏你的顺序。如果顺序很重要,你可以使用列表推导式来检查值是否已经在列表中存在:
unique = [v for i,v in enumerate(mylist) if v not in mylist[:i]]

那个解决方案有点慢,但你可以这样做:
unique = []
for tup in mylist:
    if tup not in unique:
        unique.append(tup)

第二种解决方案对于大型列表来说速度较慢,因为list.__contains__的时间复杂度是O(n)。 - timgeb
除了查看某物是否在列表中,还有其他方法可以查看它是否被使用过吗? - zondo
2
是的,在集合中存储已经看到的内容 :) - 不同之处在于集合具有O(1)成员测试。 - timgeb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接