关于排序:如何为降序值编写Python排序键函数

How to write Python sort key functions for descending values

最近版本的python从以前的cmp函数向sort()传递一个键函数,这使得我对某些对象执行复杂的排序变得更加困难。

例如,我想用一组字符串连接断开器字段对一组对象从最新到最旧进行排序。所以我希望日期的顺序是相反的,但是字符串的顺序是自然的。使用比较函数,我可以将日期字段与字符串字段的比较颠倒过来。但有了键函数,我需要找到一些方法来反转日期或字符串。

使用数字很容易(虽然很难看),只需从某个数据中减去它们,但是我是否需要找到一个相似的日期黑客(从另一个日期中减去它们,然后比较时间差?)和字符串(…我不知道如何以一种独立于区域设置的方式颠倒它们的顺序)。

我知道functools.cmp_to_key()的存在,但它被描述为"主要用作转换为python 3的程序的过渡工具,在这里比较函数不再受支持"。这意味着我应该能够用键方法做我想做的事情——但是怎么做呢?


做这件事的最通用方式是简单地将每一个键分开。Python's exporting is always stable so it is safe to do this:

1
2
sort(data, key=tiebreakerkey)
sort(data, key=datekey, reverse=True)

请(假设关键功能的相关定义)给出数据类型的下行链路日期和上行链路断裂。

注意,这是一种缓慢的方法,而不是单复合键函数的产生,因为你将完成两个完整的输出,所以如果你能产生一个复合键,它将更好,但分解为分离的输出给一系列灵活性:给每一个柱提供一个关键函数,你可以使它们与具体的组合。对任何个人的打击。

For a completely generic option:

ZZU1

而且为了完整起见,尽管我真的认为应该避免在可能的地方:

1
2
from functools import cmp_to_key
sort(data, key=cmp_to_key(your_old_comparison_function))

我认为你不应该回到n log n呼唤与n比较的比较函数,呼唤与关键函数(或2n时呼唤。


The slow-but-elegant way to do this is to create a value wrapper that has reversed ordering:

1
2
3
4
5
6
7
8
9
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个比较:

1
2
3
4
5
6
7
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))


我想码头是不完整的。我解读"基本上"这个词,是指仍然有理由使用CMP fn微软雅黑,这是其中的一个。因为它是一种"吸引人的伤害",所以被认为是一种"吸引人的伤害":人们会对它有引力,即使是爱德华1〔5〕也是一种更好的选择。

但你的案子比cmp更好,所以使用cmp_to_key来实现它。


两个字,一个键,另一个键。

这是稳定的,不改变原始列表的顺序,但必须。)

It does matter which order you do the sorts in,if you care about how equal elements get out.


一种方法是使用pandas图书馆和ARGS EDOCX1

你可以这样做,不仅仅是为了两个层次(E.G.EDOCX1[…]和EDOCX1[…]13]),而是为了任何层次的需要。

比如说,如果你有

1
2
3
4
5
6
7
d = [[1, 2, datetime(2017,1,2)],
     [2, 2, datetime(2017,1,4)],
     [2, 3, datetime(2017,1,3)],
     [2, 3, datetime(2017,1,4)],
     [2, 3, datetime(2017,1,5)],
     [2, 4, datetime(2017,1,1)],
     [3, 1, datetime(2017,1,2)]]

你可以设定你的电子邮件地址

1
df = pd.DataFrame(d)

和使用EDOCX1

1
2
3
4
5
6
7
8
9
10
11
sorted_df = df.sort_values(by=[0,1,2], ascending=[True,False,False])
sorted_list = sorted_df.agg(list, 1).tolist()


[[1, 2, Timestamp('2017-01-02 00:00:00')],
 [2, 4, Timestamp('2017-01-01 00:00:00')],
 [2, 3, Timestamp('2017-01-05 00:00:00')],
 [2, 3, Timestamp('2017-01-04 00:00:00')],
 [2, 3, Timestamp('2017-01-03 00:00:00')],
 [2, 2, Timestamp('2017-01-04 00:00:00')],
 [3, 1, Timestamp('2017-01-02 00:00:00')]]

注意到第一个柱是从上到下的,第二个和第三个柱是从上到下的,这是由于设置EDOCX1>11。


对于字符串,您可以使用一些通用的Acknowledged Maximum Value(如2 ^ 16 or 2 ^ 32)和Use Chr(),Unicode(),ord()to do the Math,just like for Integers.

在我的作品中,我知道我和UTF8中的弦乐有关,他们的命令在0xff下面,所以我写:

1
2
3
4
5
6
7
8
def string_inverse(s):
    inversed_string = ''
    max_char_val = 0xffff
    for c in s:
        inversed_string += unicode(max_char_val-ord(c))
    return inversed_string        

result.sort(key=lambda x:(x[1], string_inverse(x[0])), reverse=True)

X is of type:(string,int),so what I get is,to abuse the sql:

1
select * from result order by x[1] desc, x[0] asc;