list.sort()
函数描述 sort()
函数用于对原列表进行排序,如果指定参数,则使用指定的比较函数。
语法 1 2 3 4 5 list .sort (key=None, reverse =False ) 参数: key:主要是用来指定进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。 reverse :排序规则,reverse = True 降序, reverse = False 升序(默认)。
注意:函数无返回值,只能对列表进行排序
示例:
1 2 3 l = [1 , 5 , 6 , 3 , 2 ] l.sort(reverse=True ) print(l)
sorted()
函数描述 Python 内置的 sorted()
函数,用于对列表进行排序。使用该函数进行排序后,原列表的元素顺序不变。
语法 1 2 3 4 5 6 sorted(iterable, cmp =None, key =None, reverse =False ) sorted(iterable,key =None,reverse=False)
Python3 相比于 Python2 废弃了 cmp
参数,这个下文会说。
返回值: 返回一个新的list
reverse 参数 可指定参数 reverse
来表示升序或降序 ,True
表示降序,Fasle
表示升序。默认是升序。
1 2 3 4 sorted([5 , 2 , 3 , 1 , 4 ]) sorted([5 , 2 , 3 , 1 , 4 ], reverse=True )
key 参数 从 python2.4 开始,list.sort()
和 sorted()
函数都增加了 key
参数来指定一个函数 ,此函数将在每个元素比较前被调用 。 默认值为 None
。例如通过 key 指定的函数来忽略字符串的大小写:
1 sorted("A d c E b" .split(), key=str.lower)
key参数的值为一个函数,此函数只有一个参数且返回一个值用来进行比较。
更广泛 的使用情况是用复杂对象的某些值来对复杂对象的序列排序 ,例如:
1 2 3 4 5 6 7 8 student_tuples = [ ('john' , 'A' , 15 ), ('jane' , 'B' , 12 ), ('dave' , 'B' , 10 ), ] sorted(student_tuples, key=lambda student: student[2 ])
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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)
Python 2 在Python2 中,可以使用cmp
参数。cmp
指定一个 定制的比较函数 ,这个函数接收两个参数(iterable的元素) ,如果第一个参数小于第二个参数,返回一个负数;如果第一个参数等于第二个参数,返回零;如果第一个参数大于第二个参数,返回一个正数。cmp
的默认值为None。
如果想要升序排序 ,就要:return 1 if val1 > val2 else -1
或写成 return val1 - val2
如果想要降序排序 ,就要 return 1 if val1 < val2 else -1
或写成 return val2 - val1
注意,有没有发现上面的第一种 跟其他语言中的不太一样,比如在C++
中,一般写法是这样的:
1 2 3 4 bool cmp (int a, int b) { return a > b; return a < b; }
是不是直观感觉是反的,这是为什么呢?
这是因为cmp
中定义的规则就相当于告诉sorted()
如何对两个数进行比较,让它清楚什么样的条件是“大” ,什么样的条件是“小” 。
注意: 定义这个排序规则只是为了让sorted()
明白如何得到两个数中较“大”的那个 ,与数组最后是“从小到大”排序还是“从大到小”排序没有关系 。
此外,C++中是可以返回布尔值的,但Python中就不可以这样写,比如下面的写法就是错误的,会导致无效排序:
1 2 def cmp (a, b) : return a > b
这里因为在 Python 中,True
的值为1
, 而 False
的值为0
。
举个例子:
1 2 3 4 5 6 7 8 9 10 11 dic = {"a" : 4 , "c" : 3 , "b" : 2 , "d" : 2 }def cmp_func (val1, val2) : if val1[0 ] != val1[0 ]: return 1 if val1[0 ] < val2[0 ] else -1 else : return 1 if val1[1 ] > val2[0 ] else -1 dic = sorted(dic.items(), cmp=cmp_func) print(dic)
Python 3 Python3 废弃了 Python2 中 sorted 函数的 cmp
参数。 所以我们只能使用 key
参数进行排序,如果非要使用cmp函数进行自定义排序的话,可以借助 functools
模块中的 cmp_to_key
函数 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from functools import cmp_to_key d = {"a" : 4 , "c" : 3 , "b" : 2 , "d" : 2 }def cmp_func (val1, val2) : if val1[0 ] != val1[0 ]: return 1 if val1[0 ] < val2[0 ] else -1 else : return 1 if val1[1 ] > val2[0 ] else -1 dic = sorted(d.items(), key=cmp_to_key(cmp_func)) print(dic)
Operator 模块函数 面的 key 参数的使用非常广泛,因此 Python 提供了一些方便的函数来使得访问方法更加容易和快速。operator模块 有itemgetter
,attrgetter
,从2.6开始还增加了methodcaller
方法。使用这些方法,上面的操作将变得更加简洁和快速:
1 2 3 4 5 6 7 8 9 10 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 )] sorted(student_tuples, key=attrgetter('age' )) [('dave' , 'B' , 10 ), ('jane' , 'B' , 12 ), ('john' , 'A' , 15 )]
operator模块 还允许多级的排序,例如,先以grade,然后再以age来排序:
1 2 3 4 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 )]
sort 与 sorted 区别
sort()
是应用在 list
上的方法,sorted()
可以对所有 可迭代的对象
进行排序操作。
list
的 sort()
方法返回的是对已经存在的列表进行操作,无返回值
,而内建函数 sorted()
方法返回的是一个新的 list
,而不是在原来的基础上进行的操作。
排序的稳定性 从 Python2.2 开始,排序被保证为稳定的 。意思是说多个元素如果有相同的key,则排序前后他们的先后顺序不变 。
1 2 data = [('red' , 1 ), ('blue' , 1 ), ('red' , 2 ), ('blue' , 2 )] sorted(data, key=lambda x: x[0 ])
Python:自定义比较运算符
object 类中定义了 __lt__()
、__le__()
、__eq__()
、__ne__()
、__gt__()
、__ge__()
等方法,这组方法定义了对象之间可以使用 <
、<=
、=
、!=
、>
、>=
比较结果,也就是 python 的Rich comprison方法(富比较或厚比较) 。但由于object定义这些方法的局限性,实际使用时我们往往需要重新定义这些方法。例如:object定义的__eq__()
用is
两比较两个对象是否同一对象,并不是实质的相等性。
__ne__()
会默认调用__eq__()
,并对结果求反,因此定义了__eq__()
就相当于定义了 __ne__()
由于__lt__()
与__ge__()
互补,__le__()
与__gt__()
互补,故只需要定义__gt__()
和__ge__()
并不是每个对象都需要定义整组比较方法。如果真需要定义整组方法的行为,可以使用functools
的total_ordering
。当一个类被标注了@total_ordering
时,必须实现__eq__()
,并选择__lt__()
、__le__()
、__gt__()
、__ge__()
其中一个方法实现
举例:
有一个Number类,它有两个属性:val1
和val2
需要按以下规则比较对象的大小:
首先按照val2
的值进行比较,val2
的值越大,其对象大小越大;
val2
的值相同时,val1
的值越大,其对象大小越大
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Number : def __init__ (self, val1, val2) : self.val1 = val1 self.val2 = val2 def __eq__ (self, other) : if self is other: return True if hasattr(other, 'val1' ) and hasattr(other, 'val2' ): return self.val1 == other.val1 and self.val2 == other.val2 def __gt__ (self, other) : if self.val2 == other.val2: return self.val1 > other.val1 else : return self.val2 > other.val2 def __ge__ (self, other) : if self.val2 == other.val2: return self.val1 >= other.val1 else : return self.val2 > other.val2 number1 = Number(10 , 99 ) number2 = Number(10 , 100 ) number3 = Number(11 , 99 ) print(number1 > number2)'False' print(number3 > number1)'True'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from functools import total_ordering@total_ordering #total_ordering定义 class Number : def __init__ (self, val1, val2) : self.val1 = val1 self.val2 = val2 def __eq__ (self, other) : if self is other: return True if hasattr(other, 'val1' ) and hasattr(other, 'val2' ): return self.val1 == other.val1 and self.val2 == other.val2 def __gt__ (self, other) : if self.val2 == other.val2: return self.val1 > other.val1 else : return self.val2 > other.val2
重新回到排序 所以,如果使用了自定义比较运算符,那么将对象排序时就无需再使用key参数
或cmp参数
了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 num_list = [] num_list.append(Number(10 , 99 )) num_list.append(Number(6 , 99 )) num_list.append(Number(3 , 100 )) num_list.append(Number(6 , 100 )) num_list.sort() for i in range(4 ): print(num_list[i].val1, num_list[i].val2) num_list.sort(reverse=True ) for i in range(4 ): print(num_list[i].val1, num_list[i].val2)
Reference