python列表中字典指定value的中⽂按照⾸字母拼⾳排序数字在后情况说明
排序这种东西,极其常见了,⼀般的字典排序,列表中字典排序,都很常见。前⾯也写过了。
今⼉遇见⼀个有趣的,要将列表中字典的中⽂进⾏⾸字母排序。
实验情况
现有⼀个数据如下:
data = [{'songname': '孤芳⾃赏',
'singer': '杨⼩壮',
'songid': 7588840,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '红尘情歌',
'singer': '⾼安,⿊鸭⼦',
'songid': 7423524,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '成都-歌⼿(HD)',
'singer': '赵雷',
'songid': 7545063,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': 'a过⽕',
'singer': '张信哲',
'songid': 7000948,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
地下城与勇士音乐
{'songname': 'A男孩-歌⼿(HD)',
'singer': '梁博',
'songid': 7548187,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '3我的好兄弟',
'singer': '⼩沈阳,⾼进',
'songid': 7401487,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '告⽩⽓球(HD)',
'singer': '周杰伦',
'songid': 7523910,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0}]
排序规则:歌曲名称按照⾸字母排序,数字放在后⾯。也就是说 中英⽂歌曲在前,数字歌曲在后
使⽤⼀般的sorted来试试看。
sorted(data, key=lambda x: x.__getitem__(x["songname"]))
结果如下:
[{'songname': '3我的好兄弟',
'singer': '⼩沈阳,⾼进',余男 三级
'songid': 7401487,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': 'A男孩-歌⼿(HD)',
'singer': '梁博',
铃音免费下载
'songid': 7548187,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': 'a过⽕',
'singer': '张信哲',
'songid': 7000948,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '告⽩⽓球(HD)',
'singer': '周杰伦',
'songid': 7523910,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '孤芳⾃赏',
'singer': '杨⼩壮',
'songid': 7588840,
'song_value': 0,
'headimg': '',
'nickname': '',
五月的风
'fans_value': 0},
{'songname': '成都-歌⼿(HD)',
'singer': '赵雷',
'songid': 7545063,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '红尘情歌',
'singer': '⾼安,⿊鸭⼦',
'songid': 7423524,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0}]
由上可见,字母歌曲虽然对了,但是中⽂完全不是⼀回事,成都(chengdu) 在 孤芳⾃赏(gufangzishang)后⾯。数字在前⾯。与我们的要求⼤相径庭。
为什么会出现这种情况
Python⽐较字符串⼤⼩时,根据的是ord函数得到的编码值。基于它的排序函数sort可以很容易为数字和英⽂字母排序,因为它们在编码表中就是顺序排列的。
>> print ','< '1'<'A'<'a'<'阿'
True
但要很处理中⽂就没那么容易了。中⽂通常有拼⾳和笔画两种排序⽅式,在最常⽤中⽂标准字符集GB2312中,3755个⼀级中⽂汉字是按照拼⾳序进⾏编码的,⽽3008个⼆级汉字则是按部⾸笔画排列,
>> print '曙'< '鲑','曾'<'怡'
True True
出现这样的结果是因为‘曙’和‘曾’都是常⽤字,⽽‘鲑’和‘怡’都是次常⽤字,但⽆论从笔画还是拼⾳来看,这两对顺序都应该反过来。后来扩充的GBK和GB18030编码为了向下兼容,都没有更改之前的汉字顺序,于是sort之后的次序就很乱了。
另⼀⽅⾯unicode编码的中⽂是按《康熙字典》的偏旁部⾸和笔画数来排列的,所以排序结果和GB编码⼜不⼀样。
# encoding=utf8
char=['赵','钱','孙','李','佘']
char.sort()
for item in char:
print item.decode('utf-8').encode('gb2312')
输出是:“佘孙李赵钱”;⽽保存成gb2312编码后
# encoding=gb2312
char=['赵','钱','孙','李','佘']
char.sort()
for item in char:
print item
输出是:“李钱孙赵佘”。显然,这两个结果都不是我们想要的。那我们究竟怎样才能对中⽂正确排序呢?
先要弄清楚中⽂词典的排序规则:先按拼⾳排列,区分四声,拼⾳相同的就看笔画数⽬多少,笔画数也相同的再按笔顺中的具体笔划类型来区分,新华字典采⽤的顺序是⼀⼁⼃⼂⼄,也称作“天上⼈间”,应该没有笔划类型也完全⼀样的。所以中⽂排序不仅需要带⾳调的汉字拼⾳对照表,还需要有具体笔顺的数据。
此需求的解决办法
我的解决⽅法就是:按照中⽂转拼⾳的⽅式进⾏排序,然后切⽚重新拼接。
⾸先要获得中⽂转拼⾳的⽅式,我相信绝对有⼈遇到过这种问题,说不定连包都写好了。
果然有。
⾸先,下载包pypinyin.
pip install pypinyin
使⽤⽅式,及其完整代码如下:
演员文章身高
from pypinyin import lazy_pinyin
data = [{'songname': '孤芳⾃赏',
'singer': '杨⼩壮',
'songid': 7588840,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '红尘情歌',
'singer': '⾼安,⿊鸭⼦',
'songid': 7423524,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '成都-歌⼿(HD)',
'singer': '赵雷',
'songid': 7545063,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': 'a过⽕',
'singer': '张信哲',
'songid': 7000948,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': 'A男孩-歌⼿(HD)',
'singer': '梁博',
'songid': 7548187,
'song_value': 0,
'headimg': '',
刘欢的老婆是谁'nickname': '',
'fans_value': 0},
{'songname': '3我的好兄弟',
'singer': '⼩沈阳,⾼进',
'songid': 7401487,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '告⽩⽓球(HD)',
'singer': '周杰伦',
'songid': 7523910,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0}]
# 排序转换函数
def my_sort(data):
res = sorted(data, key=lambda i:lazy_pinyin(i["songname"]))    for i in res:
m = re.match(r"\D", i["songname"])
if m:
_ = res.index(i)
return res[_:] + res[:_]
my_sort(data)  # 调⽤函数
结果如下:
[{'songname': 'A男孩-歌⼿(HD)',
'singer': '梁博',
'songid': 7548187,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': 'a过⽕',
'singer': '张信哲',
'songid': 7000948,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '成都-歌⼿(HD)',
'singer': '赵雷',
'songid': 7545063,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '告⽩⽓球(HD)',
'singer': '周杰伦',
'songid': 7523910,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '孤芳⾃赏',
'singer': '杨⼩壮',
'songid': 7588840,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '红尘情歌',
'singer': '⾼安,⿊鸭⼦',
'songid': 7423524,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0},
{'songname': '3我的好兄弟',
'singer': '⼩沈阳,⾼进',
'songid': 7401487,
'song_value': 0,
'headimg': '',
'nickname': '',
'fans_value': 0}]
由此即可得到我们想要的结果。