jkluio668
11/21/2017 - 1:37 PM

sort1

- list.sort() 只会对list排序,不会返回排序后的list. sorted(list)会返回排序后的list,而不改变list.
- sorted(list, option):option可以定制排序:
  - option为'reverse=True'会给出逆序
  - option为'key=len'会根据元素长度排序,len会作用到list的每个元素上
  - 也可以定制自己的函数,再用key指定根据这个函数排序

使用list.sorted()方法来排序,此时list本身将被修改。通常此方法不如sorted()方便,但是如果你不需要保留原来的list,此方法将更有效。

key参数/函数
`key=str.lower`,key参数的值为一个函数,此函数只有一个参数且返回一个值用来进行比较。这个技术是快速的因为key指定的函数将准确地对每个元素调用。
更广泛的使用情况是用复杂对象的某些值来对复杂对象的序列排序:

```python
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)]
```

还可以:

```python
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)
```

## Operator 模块函数

operator模块有itemgetter,attrgetter,从2.6开始还增加了methodcaller方法。使用这些方法,上面的操作将变得更加简洁和快速:

```python
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:

```python
>>> 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)]
```

升序和降序
list.sort()和sorted()都接受一个参数reverse(True or False)来表示升序或降序排序。

```python
>>> 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)]
```

排序的稳定性和复杂排序
多个元素如果有相同的key,则排序前后他们的先后顺序不变。

对student数据先以grade降序排列,然后再以age升序排列。(评:此处最常用)

```python
>>> 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)]
```

旧的的排序方法-DSU
我们称其为DSU(Decorate-Sort-Undecorate),原因为排序的过程需要下列三步:
第一:对原始的list进行装饰,使得新list的值可以用来控制排序;
第二:对装饰后的list排序;
第三:将装饰删除,将排序后的装饰list重新构建为原来类型的list

```python
>>> 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)]
```

并不是所有的情况下都需要在以上的tuples中包含索引,但是包含索引可以有以下好处:
第一:排序是稳定的,如果两个元素有相同的key,则他们的原始先后顺序保持不变;
第二:原始的元素不必用来做比较,因为tuples的第一和第二元素用来比较已经是足够了。

此方法被RandalL.在perl中广泛推广后,他的另一个名字为也被称为Schwartzian transform。

其他语言普遍使用的排序方法-cmp函数
python2.4前,sorted()和list.sort()函数没有提供key参数,但是提供了cmp参数来让用户指定比较函数。此方法在其他语言中也普遍存在。
在python3.0中,cmp参数被彻底的移除了,从而简化和统一语言,减少了高级比较和__cmp__方法的冲突。

其实排序在内部是调用元素的__cmp__来进行的,所以我们可以为元素类型增加__cmp__方法使得元素可比较

```python
>>> Student.__lt__ = lambda self, other: self.age < other.age
>>> sorted(student_objects)
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
```

key函数不仅可以访问需要排序元素的内部数据,还可以访问外部的资源,例如,如果学生的成绩是存储在dictionary中的,则可以使用此dictionary来对学生名字的list排序:

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

**需要在处理数据的同时进行排序的话,sort(),sorted()或bisect.insort()不是最好的方法**。
在这种情况下,可以**使用heap,red-black tree或treap**。




另

实例3:对第二个关键字排序 

```python
>>>L = [('b',6),('a',1),('c',3),('d',4)]
>>>L.sort(lambda x,y:cmp(x[1],y[1]))
>>>L.sort(key=lambda x:x[1]) 
 
>>>import operator
>>>L.sort(key=operator.itemgetter(1)) 

[('a', 1), ('c', 3), ('d', 4), ('b', 6)]
```

>>> sorted(s, key=attrgetter('grade'), reverse=True)       # now sort on primary key, descending
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
```


多条件排序:
`L.sort(key=lambda x:(x[1],x[0]))`
`L.sort(key=operator.itemgetter(1,0))`