在Python 3中找到独特的不可导出的不可排序类型的最佳方法是什么

时间:2013-04-15 11:47:18

标签: python python-3.x

所以在Python 2中你可以使用像

这样的东西
>>> items = [[1, 2], [3], [3], 4, 'a', 'b', 'a']
>>> from itertools import groupby
>>> [k for k, g in groupby(sorted(items))]
[4, [1, 2], [3], 'a', 'b']

O(N log N)时间内效果很好。然而,Python 3感叹TypeError: unorderable types: int() < list()。那么在Python 3中实现它的最佳方法是什么? (我知道最好是一个主观的术语,但实际上根据Python应该有一种方法)

编辑:它不必使用排序,但我猜这将是最好的方式

2 个答案:

答案 0 :(得分:5)

在2.x中,两个无法比较的内置类型的值按类型排序。除了在解释器的一次运行期间它将保持一致时,不定义类型的顺序。因此,2 < [2]可能是真或假,但始终是真还是假。

在3.x中,无法比较的内置类型的值是无法比拟的 - 这意味着如果您尝试比较它们,它们会引发TypeError。所以,2 < [2]是一个错误。并且,至少从3.3开始,类型本身甚至不具有可比性。但是,如果您想要重现的只是2.x行为,那么它们的id绝对可以比较,并且在解释器运行期间是一致的。所以:

sorted(items, key=lambda x: (id(type(x)), x))

对于您的用例,这就是您所需要的一切。


然而,这与2.x所做的完全不同,因为这意味着,例如,1.5 < 2可能是False(因为float&gt; { {1}})。如果要复制确切的行为,则需要编写首先尝试比较值的键函数,然后在int上回退以比较类型。

这是少数几种情况之一,旧式TypeError函数比新式cmp函数更容易阅读,所以让我们写一个,然后使用{{ 3}}在它上面:

key

这仍然不能保证2.x给出的两个不同类型的值之间的顺序相同,但由于2.x没有定义任何这样的顺序(只是它在一次运行中是一致的),所以没有办法它可以。

然而,还有一个真正的缺陷:如果你定义一个对象没有完全排序的类,它们最终会排序相同,我不确定这是2.x会做的同样的事情。那种情况。

答案 1 :(得分:1)

让我们退后一步。

您想要统一集合。

如果值是可清除的,则使用O(N)set解决方案。但他们不是。如果您可以提出某种哈希函数,则可以等效地使用dict myhash(value): value。如果您的用例确实“只有可缓存的值和平坦的list可散列值”,则可以try hash执行此操作,然后再回到hash(tuple()) }。但总的来说,这不会起作用。

如果它们是完全有序的,您将使用O(N log N)sorted解决方案(或等效的,基于树的解决方案或类似方法)。如果您可以提出某种完整排序功能,则可以将key传递给sorted函数。我认为这将适用于您的用例(因此我的另一个答案)。但是,如果没有,那么O(N log N)解决方案就不会起作用了。

如果它们都不是,你可以回到O(N ** 2)线性搜索解决方案:

unique = []
for value in items:
    if value not in unique:
        unique.append(value)

如果找不到某种方法来定义值的完整排序或散列函数,那么这是你能做到的最好的。