python里有两个排序函数。sort() 是list专用的,比如list1.sort() 它本身是就地修改,无返回值。
另一个排序函数就是sorted,返回新的排序后的值。这是所有数据类型都可以用的,包括字符串等。
本文主要讨论sorted函数
参考文章:
sort、sorted排序技巧(多级排序) https://www.jianshu.com/p/d1a26a9a2496
先来一道题:
牛客网上的华为机试题
题目描述
如果统计的个数相同,则按照ASCII码由小到大排序输出 。如果有其他字符,则对这些字符不用进行统计。
实现以下接口:
输入一个字符串,对字符中的各个英文字符,数字,空格进行统计(可反复调用)
按照统计个数由多到少输出统计结果,如果统计的个数相同,则按照ASII码由小到大排序输出
清空目前的统计结果,重新统计
调用者会保证:
输入的字符串以‘\0’结尾。
输入描述:
输入一串字符。
输出描述:
对字符中的
各个英文字符(大小写分开统计),数字,空格进行统计,并按照统计个数由多到少输出,如果统计的个数相同,则按照ASII码由小到大排序输出 。如果有其他字符,则对这些字符不用进行统计。
示例1
输入
aadddccddc
输出
dca
我开始对sorted的使用不大熟悉,就写了这样的代码,虽然直观,但是哈哈:
while True:
try:
x=input()
dic={}
dic[' ']=0
#print(dic.keys())
for i in range(len(x)):
if x[i]==' ':
dic[' ']+=1
elif (ord(x[i])<=ord('9') and ord(x[i])>=ord(('0'))) or (ord('a')<=ord(x[i]) and ord(x[i])<ord('z')) or (ord('A')<=ord(x[i]) and ord(x[i])<ord('Z')):
if x[i] not in dic.keys():
dic[x[i]]=1
else:
dic[x[i]]+=1
else:
pass
keyr = sorted(dic.items(), key=lambda x: x[1], reverse=True)
for i in range(1,len(keyr)):
if keyr[i][1]==keyr[i-1][1]:
if ord(keyr[i][0])<ord(keyr[i-1][0]):
temp = keyr[i-1]
keyr[i-1]=keyr[i]
keyr[i]=temp
str1=''
for i in range(len(keyr)):
str1=str1+str(keyr[i][0])
print(str1)
except:
break
我用了一个sorted,后面针对相同个数的按照ASCII排序,我就用的 if 判断了。
(注意:sorted之后,就变成了列表list类型了,对于字典的话,列表内部是元组形式了(元组不能更改))
大神的做法呢?
import sys
while True:
s = sys.stdin.readline().strip()
if s:
dic = {}
for ch in s:
if ch not in dic:
dic[ch] = 0
dic[ch] += 1
dct = sorted(sorted(dic.items(), key=lambda x: x[0]), key=lambda y: y[1], reverse=True)
ct = ''.join([k for (k, v) in dct])
print(ct)
else:
break
比较惊喜的就是sorted的两次使用。测试输入:aabbbccc
第一次就是按照ASCII排序(用dict1.items(),得到包含键,值的元组,由于迭代对象是元组,返回值自然是元组组成的列表这里对排序的规则进行了定义,x指元组,x[1]是值,x[0]是键)
第二次就是按照数目排序。sorted()为了保持稳定性,当排序时,key相同的时候,不改变原来的位置。
反过来写,也是可以的。
dat = sorted(dic.items(), key=lambda x: x[1], reverse=True)
#第一次是按照数量降序排列
dct= sorted(dat,key=lambda x:x[0])
#第二次按照ASCII码升序,字母数字的排序,默认是按照ASCII升序
sort_result=sorted(iterable,key=lamda: 排序标准,reverse=False)
等号左边是返回值,第一个参数是排序对象,第二个是key,排序标准,第三个默认升序)。如下:
>>> 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)]
多级排序,python3已经有专用的模块了
多级排序(内置模块)opereator
【文档:https://docs.python.org/zh-cn/3.7/howto/sorting.html】
import operator
a = [(1,2,3),(3,4,5),(0,1,2)]
a.sort(key = operator.itemgetter(1,2)) #根据元组第1和第2位元素排序
print a-->[(0,1,2),(1,2,3),(3,4,5)]
operator模块有itemgetter,attrgetter,从2.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模块还允许多级的排序,例如,先以grade,然后再以age来排序:
>>> 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)]
可是这样的模块,针对我们这道题该怎么实现呢?好像还是两次sorted才能解决呢。