排序指南
作者
Dalke 和
发布版本
0.1
具有直接修改列表功能的列表有一个内置的叫作 list.sort() 的方法, 会从一个可迭代对象构建一个新的排序列表的还有一个内置那函数。
在本文档中,我们将探索使用对数据进行排序的各种技术。
基本排序
特别容易做到的升序排列甚是简便: 仅仅调用那个函数就行。该函数会返回一个全新的已完成排序动作的列表。
>>> sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]
你也能够运用一个列表的 list.sort(), 它是原地的(并且为了避免返回值是 None 而传 None), 其会少一些麻烦, 不过要是你不需要原列表, 那它也是可用的, 而它是原地的这点(并且输入 None 来避免返回值是 None)。
>>> a = [5, 2, 3, 1, 4]
>>> a.sort()
>>> a
[1, 2, 3, 4, 5]
存在另外一个区别, 那就是, list.sort() 方法仅仅是为列表所定义的, 然而, 函数能够接受任何可迭代对象。
>>> sorted({1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'})
[1, 2, 3, 4, 5]
关键函数
例如,下面是一个不区分大小写的字符串比较:
>>> sorted("This is a test string from Andrew".split(), key=str.lower)
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']
值应当是一个函数的, 是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)]
模块函数
你提供的英文内容似乎存在较多错误和不规范之处, 导致难以准确理解并进行改写。请你检查或修正一下这段英文, 以便我能较好地完成任务。
使用这些函数,上述示例变得更简单,更快捷:
>>> 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)]
模块具备的功能, 能够允许进行多级别的排序, 比如说, 先按照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)]
>>> from operator import methodcaller
>>> messages = ['critical!!!', 'hurry!', 'standby', 'immediate!!']
>>> sorted(messages, key=methodcaller('count', '!'))
['standby', 'hurry!', 'immediate!!', 'critical!!!']
升序和降序

list实行sort后的结果会和接受布尔类型值的参数产生某种关联, 此关联用于对某些有序数据集合进行从大到小排列组合例如要在一个集合中获取以学生年龄从高到低或从小到大顺序排列的数据集合:
>>> 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)]
排序稳定性和排序复杂度
>>> data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
>>> sorted(data, key=itemgetter(0))
[('blue', 1), ('blue', 2), ('red', 1), ('red', 2)]
关注blue的两条记录, 怎样去留存它们原本的秩序, 从而使得 ('blue', 1) 确保处于 ('blue', 2) 之前。
此无比美妙之属性, 可让你于一连串排序步骤里构建繁杂之排序。比如说, 若要依据grade以降序方式且age以升序方式对学生数据予以排序, 那就先对age进行排序, 接着再运用grade进行排序:
>>> s = sorted(student_objects, key=attrgetter('age')) # sort on secondary key
>>> sorted(s, key=attrgetter('grade'), reverse=True) # now sort on primary key, descending
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
它所运用的算法能够高效地开展多种排序, 原因在于其能够借助数据集中已然存在的任何排序。
使用装饰-排序-去装饰的旧方法
这个三个步骤被称为 -Sort- :
例如,要使用DSU方法按 grade 对学生数据进行排序:
>>> decorated = [(student.grade, i, student) for i, student in enumerate(student_objects)]
>>> decorated.sort()
>>> [student for grade, i, student in decorated] # undecorate
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
之所以这方法语有效, 是由于元组按字典顺序作比较, 会先去比较第一项, 要是它们相同, 就会比较第二个项目, 依照这样的方式类推下去。
不在所有情形下都必然要于装饰列表里纳入索引 i , 虽然如此, 纳入它却是存在两个益处的。
另一个名字是这个方法的, 它是在Perl程序员中被推广的, 名为L.。
使用 cmp 参数的旧方法
本HOWTO里给到的诸多结构都被假定是2.4或者更高的版本, 在这之前没有内建出来, list.sort()也不存在关键字参数, 相反, 所有的Py2.x版本都对cmp参数加以支持用以处理用户所指定的比较函数。
你提供的内容似乎存在较多错误和不清晰之处, 不太能准确理解其确切含义, 所以难以按照要求进行改写。请你检查并修正后重新提供。
在2中,sort() 是一个可用于进行某种操作的函数。它需要两个参数来进行比较, 并返回一个用于表示小于、等于或大于的值。例如, 如果它们相等则返回零, 否则返回一个用于表示大于的值。对于示例, 我们可以这样做:
>>> def numeric_compare(x, y):
... return x - y
>>> sorted([5, 2, 4, 1, 3], cmp=numeric_compare)
[1, 2, 3, 4, 5]
或者你可反转比较的顺序:
>>> def reverse_numeric(x, y):
... return y - x
>>> sorted([5, 2, 4, 1, 3], cmp=reverse_numeric)
[5, 4, 3, 2, 1]
如若在把代码从2.x移植至3.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]