遇到一道题,说是列表L=[1,6,5,3,9,12,13,33],对L进行判断,如果L是升序排列的,那么输出’UP’;如果L是降序排序的,输出’DOWN’;如果上述两者都不是,那么输出’WRONG’。
当然这个问题也不难,但是我当时采取的方法比较繁琐,先将L神拷贝给L1,然后对L1排序,再将L和L1比较。
另外一种比较简洁的方法一句话就能完成,利用了sorted()函数,如下:
print ‘UP’ if L==sorted(L) else ‘DOWN’ if L==sorted(L)[::-1] else ‘WRONG’
是不是很简洁、一目了然?所以熟悉python中众多的小函数,可以帮助我们快速编程并且很简洁。
1).sorted(L)函数和L.sort()函数
sorted(iterable[,cmp,[,key[,reverse=True]]])
作用:第一个参数是一个iterable,返回值是一个对iterable中元素进行排序后的列表(list)。
可选的参数有三个,cmp、key和reverse。
>>> L=[1,6,5,3,9,12,13,33]
>>> sorted(L)
[1, 3, 5, 6, 9, 12, 13, 33]
>>> L
[1, 6, 5, 3, 9, 12, 13, 33]
可见sorted()函数并不改变原来L的顺序,只是返回一个新的列表,这个列表是按照升序排列的。
sort()函数就不一样了,它会改变原来L的顺序。
>>> L.sort()
>>> L
[1, 6, 5, 3, 9, 12, 13, 33]
通常这个方法不如sorted(L)方便,但是List.sort()这个方法的效率要高一点。
另一个区别在于list.sort()方法只为list定义。而sorted()函数可以接收任何的iterable。
2).函数新特性(key-function模式)
从Python2.4开始,list.sort()和sorted()方法都添加了一个key参数来说明一个函数,这个函数在做比较之前会对list中的每个元素进行调用。
例如,这里是一个大小写不敏感的字符串比较:
>>> 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)
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
>>> sorted(student_tuples, key=lambda student: student[2])
# sort by age [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
同样的技术适用于有named属性的对象。例如:
>>> 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)]
3)Operator Module Functions (Operator模块中的函数)
上面的key-function模式很常见,因此Python提供了方便的函数使得祖先函数更简单和快捷。operator module有itemgetter,attrgetter,以及从Python2.6开始的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)]
operator模块支持多级排序。例如先按成绩排序,再按年龄排序:
>>> 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)]
4).升序和降序
list.sort()和sorted()都接收一个reverse参数。它是用于降序排序的标志。
例如,为了获得学生年龄的降序排序:
>>> 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)]
5).排序稳定性和复杂的排序
从Python2.2开始,排序都保证是稳定的。意思是当多个记录有相同的关键字时,它们原始的排序保留。
>>> 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)之前。
这个好的特性能让你建立复杂的排序。
例如,将学生记录按成绩降序排序、按年两升序排列。先按年龄排序,再按成绩排序。
>>> s=sorted(student_object,key=attrgettter('age'))
# sort on secondary key
>>> sorted(s,key=attrgetter('grade'),reverse=True)
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
附上一张秦时明月里面的图: