The Most Wanted Letter

chekioの問題やろうぜシリーズ


問題文

テキストが与えられるので、その中で一番頻出のアルファベットを返せっていうミッション。いくつか補足があって、

  • 大文字小文字は同じ扱い。Aとaは同じアルファベットとして扱う事。
  • カンマとかの記号も出てくるけど、それは無視する事。スペースも含む。
  • もし同じカウントのアルファベットが重複したら、abc順で一番最初に出てくるものを返す事。(つまりAが最優先でZがその逆)

最後の条件が一番厄介臭いけれど、とりあえずやってみよう!

#### 右に出てくるヒントに沿って解く方法

import string

def checkio(text: str) -> str:
    text = text.lower()
    c_list = {}
    for c in text:
        if c in string.ascii_lowercase:
            if c in c_list:
                c_list[c] += 1
            else:
                c_list[c] = 1
        
    list_of_item = list(c_list.items())
    list_of_item.sort(key=lambda t:(-t[1],t[0]))
    return list_of_item[0][0]

sortマスターになろうぜ!っていうテーマなのだと思うのだけれど、最後のlambdaを使ってのソートはなかなかレベルが高いような・・・。

でもディスカッションのスレッドで素晴らしいコメントを見つけたので紹介するよ。

sort()について。まず普通のリストに普通に掛けると、昇順で並び替えられる。当たり前だね。
l = [2,3,1]
sorted_l = l.sort()
sorted_l #[1,2,3]
で、sort()にはkeyっていう任意の引数があって、関数を指定できるようになっている。わかりすい所で言うとlenを取れば、単語の長い順にソートしてくれちゃったりする。
list_of_abc = ['aaaa', 'bbbbbbb', 'cc', 'd', 'eee']
list_of_abc.sort(key=len)

print(list_of_abc)

# ['d', 'cc', 'eee', 'aaaa', 'bbbbbbb']
で、ここにlambda関数を置いちゃえばいいんじゃね?っていうのが今回の問題のミソであり難所。普通はreverse引数を使うけれど、あえてlambdaで降順にソートしてみる。
list_of_numbers = [2, 1, 3]
list_of_numbers.sort(key=lambda x:-x)
print(list_of_numbers) #[3, 2, 1]
さらにこれを応用すると、「tupleの2番目の要素をまず昇順で並び替えて、そこから1番目の要素を降順で並び替えてね!」なんていう細かい指定も下記のように出来る。
list_of_tuples = [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]
list_of_tuples.sort(key=lambda t:(t[1], -t[0]))
print(list_of_tuples) # [(2, 'a'), (1, 'a'), (2, 'b'), (1, 'b')]