今天欣赏一个包含众多知识点的解法。是这样的:
给定两个字符串s1和s2,统计它们各自包含的各个小写字母的个数,然后互相比较。如果对某个字母,s1中出现的次数多,就打印“1:aaaa” (表示字母a在s1中出现了4次);如果s2中出现的次数多,就打印“2:aaaa”;如果次数相同,就打印“=:aaaa”。最后输出整个的比较结果,输出时先按次数排序,再按1-2-=排序,最后按字母排序。
举个例子:
s1 = "my&friend&Paul has heavy hats! &"
s2 = "my friend John has many many friends &"
mix(s1, s2) --> "2:nnnnn/1:aaaa/1:hhh/2:mmm/2:yyy/2:dd/2:ff/2:ii/2:rr/=:ee/=:ss"
分析:
这个题目其实挺简单的。统计字母个数?遍历+字典轻松搞定。比较两个字典?逐个即可。最后输出的先按...排序,再按...排序,最后按...排序?有点麻烦,不过用itemgetter也可以做到。
但是,这里我想请大家一起欣赏一下这个,非常利落:
from collections import Counterdef mix(s1, s2): c1 = Counter(filter(str.islower, s1)) c2 = Counter(filter(str.islower, s2)) res = [] for c in set(c1.keys() + c2.keys()): n1, n2 = c1.get(c, 0), c2.get(c, 0) if n1 > 1 or n2 > 1: res.append(('1', c, n1) if n1 > n2 else ('2', c, n2) if n2 > n1 else ('=', c, n1)) res = ['{}:{}'.format(i, c * n) for i, c, n in res] return '/'.join(sorted(res, key=lambda s: (-len(s), s)))
解析:
1. filter:
filter(function, sequence)对sequence中的item依次执行function(item),将执行结果为True的item组成一个List/String/Tuple(取决于sequence的类型)返回。
对于s1="my&friend&Paul has heavy hats! &",filter(str.islower, s1)为取出其中的所有小写字母:
'myfriendaulhasheavyhats'
2. Counter:
Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。
Counter(filter(str.islower, s1))的结果为:
{'a': 4, 'h': 3, 'e': 2, 's': 2, 'y': 2, 'd': 1, 'f': 1, 'i': 1, 'm': 1, 'l': 1, 'n': 1, 'r': 1, 'u': 1, 't': 1, 'v': 1}
3. 合并遍历2个字典:
for c in set(c1.keys() + c2.keys()):
4. 根据tuple合成一个字符串列表:
res = ['{}:{}'.format(i, c * n) for i, c, n in res]
5. 多重排序:
对于['2:aa', '2:ee', '2:dd', '=:gg', '1:ii', '1:ooo', '=:nnn', '2:sss', '1:uuu']这样一个列表,如何先按照次数(字符串长度)、再按照1-2-=、最后按照字母排序?
用lambda指定sorted的key参数:
sorted(res, key=lambda s: (-len(s), s))
相当于先按照s的长度从大到小(-len(s))排序,再按照s的字母数字排序(1>2>=, 1:aa>1:bb)。