1、sorted(iterable[, key][, reverse])
从Iterable中的项返回新的排序列表。
有两个指定关键字的可选参数:[, key]、[, reverse]。
key指定一个参数的函数,该函数用于从每个列表元素中提取比较key:key=str.lower。默认值为None(直接比较元素)。
reverse是一个布尔值。如果设置为True,则列表元素将进行排序,就好像每个比较都颠倒了一样。
2、用法
Python列表有一个内置的list.sort()方法,可以直接修改列表。还有一个sorted()内置函数,它从一个iterable构建一个新的排序列表。
2.1 简单的升序排序
只需调用sorted()函数。它返回一个新的排序列表:
>>> sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]
还可以使用list.sort()方法。它直接修改列表(并返回NONE以避免混淆)。通常它不如sorted()方便,但是如果您不需要原始列表,它的效率会稍微高一些。
>>> a = [5, 2, 3, 1, 4]
>>> a.sort()
>>> a
[1, 2, 3, 4, 5]
另一个不同之处在于list.sort()方法仅为列表定义。相反,sorted()函数接受任何iterable对象。
>>> sorted({1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'})
[1, 2, 3, 4, 5]
2.2 Key 功能
list.sort()和sorted()都有一个key参数,用于指定在进行比较之前要在每个列表元素上调用的函数。
例如,下面是不区分大小写的字符串比较:
按每个元素首字母的顺序排列,小写字符排在大写字母前。
>>> sorted("This is a test string from Andrew".split(), key=str.lower)
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']
一种常见的模式是使用对象的一些索引作为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)]
2.3 Operator模块功能
上面显示的key-function模式非常常见,因此Python提供了方便的函数来使访问器函数更容易、更快。操作符模块有itemgetter()、attrgetter()和method caller()函数。
from operator import itemgetter, attrgetter
student_tuples = [\
('john', 'A', 15),\
('jane', 'B', 12),\
('dave', 'B', 10),\
]
>>> sorted(student_tuples, key=itemgetter(2))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
from operator import itemgetter, attrgetter
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=attrgetter('age'))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
Operator模块函数允许多级排序。例如,要按年级然后按年龄排序,请执行以下操作:
from operator import itemgetter, attrgetter
student_tuples = [\
('john', 'A', 15),\
('jane', 'B', 12),\
('dave', 'B', 10),\
]
>>> sorted(student_tuples, key=itemgetter(1,2))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
from operator import itemgetter, attrgetter
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=attrgetter('grade', 'age'))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
2.4 升序和降序
list.sorted()和sorted()都接受带有布尔值的reverse 参数。这用于标记降序排序。例如,要以相反的年龄顺序获取学生数据,请执行以下操作:
from operator import itemgetter, attrgetter
student_tuples = [\
('john', 'A', 15),\
('jane', 'B', 12),\
('dave', 'B', 10),\
]
>>> sorted(student_tuples, key=itemgetter(2), reverse=True)
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
from operator import itemgetter, attrgetter
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=attrgetter('age'), reverse=True)
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
2.5 排序稳定性与复杂排序
保证排序是稳定的。这意味着当多个记录具有相同的key时,它们的原始顺序将被保留。
例如:
from operator import itemgetter
data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
>>> sorted(data, key=itemgetter(0))
[('blue', 1), ('blue', 2), ('red', 1), ('red', 2)]
注意:由于原始列表中,(‘blue’,1)在(‘blue’,2)前面,所以排序后列表(‘blue’,1)还在(‘blue’,2)前面。
这个奇妙的属性允许您在一系列排序步骤中构建复杂的排序。例如,要先按grade降序再按age升序对学生数据进行排序,请先执行age排序,然后使用grade再次排序:
from operator import itemgetter, attrgetter
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),\
]
>>> 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)]
Python中使用的TimSort算法高效地执行多个排序,因为它可以利用数据集中已有的任何排序。