• 关于Python的多重排序


    Python预置的list.sort()、sorted()方法可实现各种数组的排序,但支持的只限于一个key,如果要多重排序,目前所知的方法只有自定义了。

    Help on built-in function sorted in module __builtin__:

    sorted(...)

        sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list

    查看sorted的帮助可知,cmp参数在第二个位置,不过一般都以kwargs的形式显式写出。

    关于cmp,cmp定义的函数接收源数组中相邻的两个元素,在比较大小后分别返回负值、0或正值,分别代表第一个值小于、等于或大于第二个值,然后再按照key和reverse的设定去进行排序。

    >>> a=list(range(10))
    >>> a.reverse()    # reverse为on place方法
    >>> a
    [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
    >>> a.sort(cmp=lambda a,b: a-b)    # a-b < 0  默认reverse为False,升顺排序,结果为正常顺序
    >>> a
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> a.sort(cmp=lambda a,b: b-a)    # b-a > 0  lambda返回正值,认为a > b,按照“升顺”排序,实际结果为降序
    >>> a                              # sort同样是on place方法
    [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
    >>> 

    对于多重排序,可利用cmp方法,分别定义key的优先级,以及排序方式,达到多重、独立顺序的排序方式实现。

    代码如下:

    d1 = {1:23, 'b': 62}
    d2 = {1:24, 'b': 2}
    d3 = {1:23, 'b': 54}
    d4 = {1:23, 'b': 1}
    d5 = {1:01, 'b': 9}
    d6 = {1:23, 'b': 32}
    d7 = {1:05, 'b': 33}
    d8 = {1:39, 'b': 100}
    
    li = [d1, d2, d3, d4, d5, d6, d7, d8]
    
    def cmpf(a, b, key1, key2):
         if (a[key1] != b[key1]):
                 return a[key1] - b[key1]
         else:
                 return a[key2] - b[key2]
    
    def rcmpf(a, b, key1, key2):
         if (a[key1] != b[key1]):
                 return b[key1] - a[key1]
         else:
                 return a[key2] - b[key2]
    
    # key1、key2均为升序
    sorted(li, cmp=lambda a,b: cmpf(a, b, 1, 'b'))
    
    # key1降序、key2升序
    sorted(li, cmp=lambda a,b: rcmpf(a, b, 1, 'b'))

    执行结果如下:

    >>> sorted(li, cmp=lambda a,b: cmpf(a, b, 1, 'b'))
    [{1: 1, 'b': 9}, {1: 5, 'b': 33}, {1: 23, 'b': 1}, {1: 23, 'b': 32}, {1: 23, 'b': 54}, {1: 23, 'b': 62}, {1: 24, 'b': 2}, {1: 39, 'b': 100}]
    >>> 
    >>> sorted(li, cmp=lambda a,b: rcmpf(a, b, 1, 'b'))
    [{1: 39, 'b': 100}, {1: 24, 'b': 2}, {1: 23, 'b': 1}, {1: 23, 'b': 32}, {1: 23, 'b': 54}, {1: 23, 'b': 62}, {1: 5, 'b': 33}, {1: 1, 'b': 9}]
    >>> 

    可以看到混合排序结果正常。

    PS:按照预想,这种方式应该适用于所有可以指定多个key的数据结构,不过仍待验证。

    对于Python3,sort方法取消了cmp参数,官方给出的解决方案是进行多次排序,优先级低的字段先排序,然后逐个根据优先级高的字段排序

    >>> d1 = {1:23, 'b': 62}
    >>> d2 = {1:24, 'b': 2}
    >>> d3 = {1:23, 'b': 54}
    >>> d4 = {1:23, 'b': 1}
    >>> d5 = {1:1, 'b': 9}
    >>> d6 = {1:23, 'b': 32}
    >>> d7 = {1:5, 'b': 33}
    >>> d8 = {1:39, 'b': 100}
    >>> li = [d1, d2, d3, d4, d5, d6, d7, d8]
    >>> li.sort(key=lambda e: e['b'])  # 现根据'b'进行排序,优先级较低
    >>> pprint(li)
    [{1: 23, 'b': 1},
     {1: 24, 'b': 2},
     {1: 1, 'b': 9},
     {1: 23, 'b': 32},
     {1: 5, 'b': 33},
     {1: 23, 'b': 54},
     {1: 23, 'b': 62},
     {1: 39, 'b': 100}]
    >>> li.sort(key=lambda e: e[1])  # 再根据1进行排序,优先级高于'b'
    >>> pprint(li)
    [{1: 1, 'b': 9},
     {1: 5, 'b': 33},
     {1: 23, 'b': 1},
     {1: 23, 'b': 32},
     {1: 23, 'b': 54},
     {1: 23, 'b': 62},
     {1: 24, 'b': 2},
     {1: 39, 'b': 100}]
    >>> 
  • 相关阅读:
    如何删除PHP数组中的元素,并且索引重排(unset,array_splice)?
    Windows下,MySQL root用户忘记密码解决方案
    MySQL 5.5开启慢查询功能
    MySQL Cluster导入数据表时报错:Got error 708 'No more attribute metadata records (increase MaxNoOfAttributes)' from NDBCLUSTER
    MySQL Cluster在线添加数据节点
    关闭Linux防火墙(iptables) 及 SELinux
    MySQL Cluster 7.3.5 集群配置实例(入门篇)
    磁盘爆满导致MySQL无法启动:Disk is full writing './mysql-bin.~rec~' (Errcode: 28). Waiting for someone to free space...
    cocos2dx 3.1创建工 mac
    跟我一起学extjs5(05--主界面上增加顶部和底部区域)
  • 原文地址:https://www.cnblogs.com/harelion/p/4934407.html
Copyright © 2020-2023  润新知