参数key的功能非常强大,因为几乎所有函数,无论是内置函数还是用户自定义函数,都可以用来控制输出顺序。
如果排序要求是按照每个字符串的最后一个字母对可迭代序列进行排序(如果最后一个字母是相同的,就使用倒数第二个字母),那么就可以定义一个函数用来排序。下面的例子定义了一个函数,其功能是反转字符串序列,然后将该函数作为参数传递给key:
word[::-1]用于反转字符串。reverse_word()将会作用于每一个元素,而且排列顺序将会取决于最后的字符。
你可以在参数中定义lambda函数来代替编写一个独立的函数。
lambda函数是一个匿名函数:
1.必须是内联定义
2.没有名称
3.不能包含语句
4.像函数一样执行
在下面的例子中,参数key被设置为一个没有名称的lambda函数,lambda的参数是x,x[::-1]是对参数执行的操作:
对每个元素调用x[::-1]并反转单词。反转后的单词被用于排序,但是返回的仍然是原始的单词。
如果需求发生了变化,并且顺序也应该颠倒,那么reverse关键字可以和key参数一起使用:
当你需要根据属性对类对象排序时,lambda函数也很有用。如果你有一组学生,需要根据他们的最终成绩按照从高到低的顺序对他们进行排序,那么lambda可以用来从类中获取grade属性:
lambda在每个元素上调用getattr()函数并返回grade的值。
将reverse设置为True,使升序输出变为为降序输出,以便使成绩最高的排在第一位。
当你同时使用sorted()函数中的key和reverse参数时,如何实现排序的可能性是无穷无尽的。当你为一个小函数使用基本lambda式时,代码可以保持简短和整洁,或者你可以编写一个全新的函数,导入它,并在key参数中使用它。
使用.sort()对值排序
名称非常相似的.sort()与内置的sorted()有很大的差别。它们或多或少得完成了相同的事情,但是list.sort()的help()文档强调了二者之间最重要的两个区别:
第一,sort是list类的一个方法,只能与list一起使用。它不是一个内置的迭代器。
第二,.sort()返回None并改变值的位置。让我们看一下这两种代码差异的影响:
在这个代码示例中,.sort()与sorted()的操作方式有一些非常显著的差异:
1..sort()没有有序的输出,因此对新变量的赋值只传递None类型
2.values_to_sort列表的顺序已经发生了改变,而且原始顺序也并没有以任何形式保留下来。
这些行为上的差异使得.sort()和sorted()在代码中绝对不可互换,如果以错误的方式使用它们,可能会产生意想不到的结果。
.sort()具有与sorted()相同的key和reverse这种可选的关键字参数,这些参数具有与sorted()相同的强大的功能。在这里,你可以根据第三个单词的第二个字母对短语列表进行排序,然后逆序返回列表:
在本例当中,lambda函数被用来完成以下功能:
1.把每个短语分成一个单词列表
2.找到本例中的第三个元素或单词
3.找到第三单词中的第二个字母
何时使用sorted()和.sort()
你已经看到了sorted()和.sort()之间的区别,但是什么时候该用哪一个呢?
让我来说一下,有一个5k比赛即将到来:第一届年度Python 5k。需要捕获并排序来自比赛的数据。需要捕获的数据是跑步者的号码和完成比赛所需的秒数:
当参赛者跨过终点线时,每一个Runner都会被加入一个名为runners的列表当中。在5k比赛中,并不是所有的运动员都同时跨过起跑线,所以第一个越过终点线的人可能并不是最快的:
每一次一个跑步者跨过终点线,他们的号码以及耗时(以秒为单位)都会被加入到runners列表当中。
现在,负责处理结果数据的程序员看到了这个列表,知道了前5名最快的选手是获奖者,其余的参赛者将按时间排序。
不需要根据不同的属性进行多种类型的排序。这个列表的大小是合理的。没有提到将列表存储在某个地方。只需要按时间排序,找出耗时最短的5名选手:
编程人员选择在参数key上使用lambda函数,以便从每一个runner中获取它们的持续时间属性,并且使用.sort()对runners列表进行排序。在runners列表完成排序之后,前5个元素被存储在top_five_runners列表中。
任务完成!比赛总监过来告诉程序员,由于Python的当前版本是3.7,所以他们决定每37名冲过终点线的人将获得一个免费的健身包。
此时,程序员开始感到很苦恼,因为runners列表已经不可逆转地更改了,没有办法恢复原始的runners列表的顺序,并找到每37人。
如果您正在处理重要的数据,即使这些原始数据需要恢复的可能性很小,那么.sort()也不是最佳选项。如果数据是副本,如果它是不重要的工作数据,如果没有人介意丢失它,因为它可以被找回,那么.sort()是一个不错的选择。
或者,runners列表可以使用sorted()函数排序,并且使用相同的lambda表达式:
在使用sorted()函数的这个方案中,原始的runners列表仍然是完整的,没有被覆盖。通过与原始值的交互,可以实现每隔37人到达终点线的临时性要求:
every_thirtyseventh_runners列表是对runners列表使用列表切片语法创建的,它仍然包含跑步者越过终点线的原始顺序。
怎样使用Python排序:结论
.sort()和sorted()可以提供所需的排序顺序,如果你正确地将它们与可选的关键字参数reverse和key一起使用的话。
当涉及到输出和修改数据时,两者具有非常不同的特性,因此请确保您仔细考虑过将使用.sort()的任何应用功能或程序,因为它会不可逆转地覆盖数据。
对于热心寻找排序方面的挑战的Python高手来说,可以尝试在排序中使用更复杂的数据类型:嵌套迭代器。
英文原文:https://realpython.com/python-sort/
译者:Lyx