python排序……根据汉字拼音排序; 相邻元素比较排序
现在我们有个联系人名单, 想要对其按照拼音排序, 就像微信的通讯录一样, 应该怎么做, 如下是随便写的。
zh_names = ["李大", "刘老三", "王富贵", "牛二娃", "毕姥爷", "赵匡胤", "朱元璋", "铁木真", "李世民", "朱由检", "王莽", "嬴政", "刘邦", "项羽", "貂蝉", "赵飞燕", "曹操", "孙权", "司马懿", "杨坚", "武松", "宋江", "晁盖", "李逵", "胡汉三", "阿斌", "狄仁杰", "寇准", "包拯", "张居正", "霍去病", "蒙恬"] |
这个时候首先想到的肯定是内置的sorted函数, 如下所示:
sorted(zh_names) |
显然sorted函数默认按照字符编码来排序的, 如果给英文排序肯定没啥问题, 换成中文了排序失去了意义, 别说用户了, 向我们这些人也搞不清阿斌和赵匡胤在字符编码里的相对位置。
所以还是要按照汉字拼音的字母顺序来排列是最为合理的。
我们的第一步需要获取汉字拼音, 推荐使用pypinyin模块,
pypinyin模块
pypinyin模块基本上能满足你所有的汉字转拼音需求, 主要两个函数lazy_pinyin和pinyin, 两者本质上没有区别。
更多使用方法参考官方文档, 比较友好的是官方文档是用中文编写的, 所以直接dir; help结果就是中文。
接下来看一个简单演示,
# 导入的时候重命名, 提高可读性, 降低命名冲突 |
第二个参数是输出格式, 我们分别使用了纯字母格式, 声调格式和首拼格式, 更多格式查阅文档。
如下是Style类型的简要说明
NORMAL = 0 # 纯字母格式, lazy_pinyin默认使用该格式 |
sorted函数的第二个参数
知道如何获取汉字拼音后, 接下来的事情就是在sorted函数传入排序依据。
我们知道sorted第一个参数接受一个迭代器, 列表; 字典; 元组等等, 第二个关键字参数接受一个函数, 该函数需要一个参数。
sorted函数在迭代器的每一个元素上调用该函数, 根据该函数的返回值给迭代器排序。
语言描述不好理解, 看例子。
from pypinyin import lazy_pinyin |
实际上我们不需要单独定义key_pinyin函数, 调用lambda表达式就可以了。
result = sorted(zh_names, key=lambda e: "".join(lazy_pinyin(e))) |
如果排序依据函数代码比较长或者在多个地方调用这段代码, 那么定义单独函数, 如果是一次性的而且处理代码比较短, 那么使用lambda表达式。
排序依据函数太长, 我们简称key函数吧!
sorted函数在每一个迭代器元素上调用key函数, 参照其返回值对迭代器排序。
key函数返回每个元素的拼音首拼, 之后sorted根据这些拼音给整个中文姓名排序。
cmp_to_key
现在我们遇到这样一个场景, 给学生成绩排序, 排序依据是主修课总成绩, 如果两个学生的主修课总成绩相同的话根据选修课总成绩来排序。
scores = [{"major": 85, "elective": 70}, |
一共六个考生但是只能录取五个名额, 其中三名考生主修课总成绩相同。 看运行结果:
90, 68 |
正确结果是录取选修成绩为75分的学生, 但是我们的程序录取了选修成绩为70分的学生, 显然不公平, 引起了考生不满。
这个时候很自然的想到给key函数增加第二个参数, 可惜报错了。
..... |
错误输出如下:
Traceback (most recent call last): |
所以这里我们需要一个转换器, 在functools模块里, 正确代码如下。
from functools import cmp_to_key |
顾名思义cmp_to_key函数把cmp函数转换成了key函数。
当然cmp函数也可以使用lambda表达式, 也要看具体场景。
cmp函数和key函数有一些区别, 需要格外注意。
key函数接受一个参数, 而cmp函数接受两个参数, 是相邻的迭代器元素
key函数返回处理元素后的结果, 而cmp函数返回相邻两个元素的比较结果
最后看下输出结果:
90, 68 |
python排序总结
最后给python排序做个总结, 基本上能解决所有的排序需求。
sorted函数对迭代器排序, 结果返回新副本, 列表的sort方法原地排序, 结果修改当前列表
key函数处理元素返回排序依据
cmp函数比较相邻的两个元素返回比较结果, sorted根据比较结果对迭代器排序
cmp需要做转换, 使用functools模块的cmp_to_key函数
总体上没有特殊需要使用key函数就可以了, 而其他语言肯定是cmp函数形式,
所以如果有其他语言的经验还是优先使用key函数吧, 不要先入为主, 刚开始我就是先入为主不太理解key函数。