python 内建排序 HOW TO

list.sort()与sorted()


python 有两个内建排序函数:一个是list.sort(),对调用该函数的list进行原地排序;另一个是sorted(),可以对任意迭代器进行排序,返回list类型的序列。二者有两个区别。


第一,list.sort()没有返回值,只对list原地排序;而sorted()将排序后序列作为新list返回,如下实例:

>>> sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]

>>> a = [5, 2, 3, 1, 4]
>>> a.sort()
>>> a
[1, 2, 3, 4, 5]


第二,list.sort()只应用于list,而sorted()可用于任意迭代器,如下实例:

>>> sorted({1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'})
[1, 2, 3, 4, 5]


另外,二者都有相同参数:1.key  2.reverse  3.cmp,并且使用方法相同,下面通过sorted()进行详细说明




key参数的使用


基本说明:

key参数指定一个函数,这个函数的实参为每个迭代器的item,经过该函数运算,返回值为每个item中需要进行对比的项(key),如下实例:

>>> sorted("This is a test string from Andrew".split(), key=str.lower)
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']

简单说,key参数值必须是一个函数,且这个函数只有一个参数,并且返回一个key值,作为比较使用。



使用实例说明:

通常情况下,对于复杂结构进行排序,通常使用索引作为比较的key,例如:

>>> student_tuples = [
    ('john', 'A', 15),
    ('jane', 'B', 12),
    ('dave', 'B', 10),
]
>>> sorted(student_tuples, key=lambda student: student[2])   # sort by age
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

类似的排序方式,也可以用于类,例如:

>>> class Student:
        def __init__(self, name, grade, age):
            self.name = name
            self.grade = grade
            self.age = age
        def __repr__(self):
            return repr((self.name, self.grade, self.age))

>>>

>>> student_objects = [
    Student('john', 'A', 15),
    Student('jane', 'B', 12),
    Student('dave', 'B', 10),
]
>>> sorted(student_objects, key=lambda student: student.age)   # sort by age
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]



使用Operator模块

由于以上使用key参数的方式十分普遍,python提供了相关函数,使以上方式的使用更加简单快捷。


operator模块提供了 operator.itemgetter(),operator.attrgetter()函数,在 Python 2.5以后还提供了operator.methodcaller() 函数。使用这些函数可以让上节描述的排序方法更加快捷方便:

>>> from operator import itemgetter, attrgetter

>>>

>>> sorted(student_tuples, key=itemgetter(2))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

>>>

>>> sorted(student_objects, key=attrgetter('age'))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]


operater模块提供的函数,可以进行多级排序. 如下实例, 先以grade排序,再以 age排序:

>>> sorted(student_tuples, key=itemgetter(1,2))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]

>>>

>>> sorted(student_objects, key=attrgetter('grade', 'age'))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]


operator.methodcaller()函数可以调用方法,操作需要比较的item后,然后对item进行比较。如下实例,str.count()方法对每个item的感叹号进行统计,按照包含感叹号的多少进行排序:

>>> messages = ['critical!!!', 'hurry!', 'standby', 'immediate!!']
>>> sorted(messages, key=methodcaller('count', '!'))
['standby', 'hurry!', 'immediate!!', 'critical!!!']

reverse参数的使用

reverse参数很好理解,如果reverse=True,将以降序排序,如下实例:

>>> sorted(student_tuples, key=itemgetter(2), reverse=True)
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

>>>

>>> sorted(student_objects, key=attrgetter('age'), reverse=True)
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]


cmp参数的使用(不推荐)

在python2.4以前,排序没有key参数,所有进行自定义排序,使用的都是cmp参数。而在python 3开始,就没有cmp参数了,另外cmp参数没有key运行得快,所以这里只做简单说明,建议大家尽量使用key参数进行排序


cmp参数值是一个有两个参数的函数,该函数参数的实参也是需要比较的item,通过该函数进行计算,返回的结果如果为负数,证明item1<item2,若为0,证明item1=item2,为正数,证明item1>item2。如下例子:

>>> def numeric_compare(x, y):
        return x - y
>>> sorted([5, 2, 4, 1, 3], cmp=numeric_compare)
[1, 2, 3, 4, 5]

刚才说道python3.x不支持cmp参数,如何将python2.x程序迁移到python3.x呢?使用下述方法:

def cmp_to_key(mycmp):
    'Convert a cmp= function into a key= function'
    class K(object):
        def __init__(self, obj, *args):
            self.obj = obj
        def __lt__(self, other):
            return mycmp(self.obj, other.obj) < 0
        def __gt__(self, other):
            return mycmp(self.obj, other.obj) > 0
        def __eq__(self, other):
            return mycmp(self.obj, other.obj) == 0
        def __le__(self, other):
            return mycmp(self.obj, other.obj) <= 0
        def __ge__(self, other):
            return mycmp(self.obj, other.obj) >= 0
        def __ne__(self, other):
            return mycmp(self.obj, other.obj) != 0
    return K


>>> sorted([5, 2, 4, 1, 3], key=cmp_to_key(reverse_numeric))
[5, 4, 3, 2, 1]

在python2.7以后,functools.cmp_to_key() 可直接通过functools进行调用



另外一些说明

一、为类组成的列表,提供默认的排序方法

在类中将排序中作为key的属性,加入相关比较的方法中,如下:

>>> Student.__eq__ = lambda self, other: self.age == other.age
>>> Student.__ne__ = lambda self, other: self.age != other.age
>>> Student.__lt__ = lambda self, other: self.age < other.age
>>> Student.__le__ = lambda self, other: self.age <= other.age
>>> Student.__gt__ = lambda self, other: self.age > other.age
>>> Student.__ge__ = lambda self, other: self.age >= other.age
>>> sorted(student_objects)
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]


一般以实现这六种比较方法为佳,另外可以使用functools.total_ordering()修饰,可以简化代码量


二、key参数的另一种用法

key参数不只依赖被排序的实例,可以使用额外的实例作为key。如下例子:student 成绩存在一个字典中, 此字典可以用于给另一个包含student姓名的list排序::

>>> students = ['dave', 'john', 'jane']
>>> grades = {'john': 'F', 'jane':'A', 'dave': 'C'}
>>> sorted(students, key=grades.__getitem__)
['jane', 'dave', 'john']

参考:

http://docs.python.org/2/howto/sorting.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值