在最新版本的Python中,将关键函数从先前的cmp函数传递给sort()
,这使得我更难对某些对象执行复杂的排序。
例如,我希望从最新到最旧对一组对象进行排序,其中包含一组字符串附加字段。所以我希望日期的顺序是相反的,但是字符串的顺序是自然的。使用比较函数,我可以将日期字段与字符串字段的比较颠倒过来。但是对于键函数,我需要找到一些方法来反转/反转日期或字符串。
处理数字很容易(虽然很难看)--只需从某些东西中减去它们--但我是否必须为日期找到类似的技巧(从另一个日期中减去它们,然后比较时间增量?)和字符串(...I不知道如何以独立于语言环境的方式颠倒它们的顺序)。
我知道functools.cmp_to_key()
的存在,但它被描述为“主要用作转换为Python3的程序的过渡工具,而Python3不再支持比较功能”。这意味着我应该能够用key方法做我想做的事情--但是如何做呢?
发布于 2012-06-26 20:42:36
要做到这一点,一种缓慢而优雅的方法是创建一个反向排序的值包装器:
from functools import total_ordering
@total_ordering
class ReversedOrder:
def __init__(self, value):
self.value = value
def __eq__(self, other):
return other.value == self.value
def __lt__(self, other):
return other.value < self.value
如果你没有functools.total_ordering
,你将不得不实现所有6个比较,例如:
import operator
class ReversedOrder:
def __init__(self, value):
self.value = value
for x in ['__lt__', '__le__', '__eq__', '__ne__', '__ge__', '__gt__']:
op = getattr(operator, x)
setattr(ReversedOrder, x, lambda self, other, op=op: op(other.value, self.value))
发布于 2012-06-26 20:26:53
要做到这一点,最通用的方法是简单地依次按每个键分别排序。Python的排序总是稳定的,所以这样做是安全的:
sort(data, key=tiebreakerkey)
sort(data, key=datekey, reverse=True)
将(假设关键函数的相关定义)为您提供按降序日期和升序平局排序的数据。
请注意,这种方式比生成单个组合键函数要慢,因为您最终将执行两个完整的排序,所以如果您可以生成一个组合键,这会更好,但将其拆分成单独的排序可以提供很大的灵活性:给定每个列的一个键函数,您可以对它们进行任意组合,并为任何单独的列指定reverse。
对于完全通用的选项:
keys = [ (datekey, True), (tiebreakerkey, False) ]
for key, rev in reversed(keys):
sort(data, key=key, reverse=rev)
为了完整性,尽管我真的认为应该尽可能地避免这样做:
from functools import cmp_to_key
sort(data, key=cmp_to_key(your_old_comparison_function))
我认为您应该避免这种情况的原因是,与对关键函数的n
调用(或当您进行两次排序时的2n
调用)相比,对比较函数的n log n
调用。
发布于 2012-06-26 20:41:09
我认为文档不完整。我对“主要”这个词的解释是,仍然有理由使用cmp_to_key,这就是其中之一。尽管key
是一个更好的选择,但cmp
被移除是因为它是一个“吸引人的麻烦”:人们会被它所吸引。
但是您的情况显然更适合作为cmp
函数,所以使用cmp_to_key
来实现它。
https://stackoverflow.com/questions/11206884
复制相似问题