今回もちょっとしたコーディング問題から。
次のような文字列のリストがあります。
WORDS = ['this', 'is', 'ordereddict', 'an', 'elementary', 'test', 'example', 'hippopotamus']
これらの文字列の中から、同じ文字 ( character / letter ) が最も多く使われている単語を選び出して返す関数を作成します。
出力結果は以下のようになります。
ordereddict: 'd' 3 times
elementary: 'e' 3 times
hippopotamus: 'p' 3 times
何故かというと...
'this': 同じ文字は使われていません。
'is': 同じ文字は使われていません。
'ordereddict': 'd' が 3 回使われています。
'an': 同じ文字は使われていません。
'elementary': 'e' が 3 回使われています。
'test': 't' が 2 回使われています。
'example': 'e' が 2 回使われています。
'hippopotamus': 'p' が 3 回使われています。
ですから、同じ文字が 3 回使われている 3 つの単語を、最も多く登場する文字とその回数の情報も含めて返しています。
今回の問題を解決する際に役に立つのが、collections モジュールの Counter クラスと、そのクラスの most_common() メソッドです。
Counter クラスは dict のサブクラスで、与えられたシーケンスの要素をキー、その要素の出現数を値とするコレクション ( Counter オブジェクト ) です。
from collections import Counter
c = Counter('reindeer')
print(c)
# Counter({'e': 3, 'r': 2, 'i': 1, 'n': 1, 'd': 1})
そして、Counter オブジェクトの most_common() メソッドを利用すると、出現頻度の高い ( 辞書要素の中で値が大きい ) 順に並べられたタプルのリストを取得することが出来ます。
print(c.most_common())
# [('e', 3), ('r', 2), ('i', 1), ('n', 1), ('d', 1)]
最も値の大きいもの一つだけを取得したい場合は、most_common() メソッドに 1 を渡します。
print(c.most_common(1))
# [('e', 3)]
では実装チャレンジです!
制限時間: 50 分
from collections import Counter
WORDS = ['this', 'is', 'ordereddict', 'an', 'elementary', 'test', 'example', 'hippopotamus']
def most_repeated_word(words):
pass
出力結果:
ordereddict: 'd' 3 times
elementary: 'e' 3 times
hippopotamus: 'p' 3 times
いかがでしたか?
Counter.most_common() の返却値はタプルのリストで、タプルのインデックス 0 に文字、インデックス 1 に出現回数を表す値が入っていますから、それを取り出そうとするとインデックス表記で目がチカチカするコードになってしまいます。
そこで、同じ collections モジュールの namedtuple も活用してみました。
これにより、タプルの各要素にインデックス番号だけではなく、属性名でアクセス可能になります。
また、1 つの文字列 (単語) を解析するためのヘルパー関数 count_letters() を作成しました。
実装例は以下のようです。参考にしてください。
from collections import Counter, namedtuple
ParseWord = namedtuple('ParseWord', ('word', 'letter', 'count'))
def count_letters(word):
c = Counter(word).most_common(1)[0]
return ParseWord(word=word, letter=c[0], count=c[1])
上の count_letters() に 'test' が渡されてきた場合、
1: Counter(word) で、Counter({'t': 2, 'e': 1, 's': 1}) オブジェクトが作成され、
2: Counter(word).most_common(1) で、[('t', 2)] が返されてくるので、
3: Counter(word).most_common(1)[0] で、('t', 2) が取得できます。
3: が 'test' を解析した結果最も多く含まれている文字とその回数を表すタプルです。
def most_repeated_word(words):
result = []
for word in words:
result.append(count_letters(word))
sorted_words = sorted(result, key=lambda x: x.count, reverse=True)
max_letter_count = sorted_words[0].count
return [word for word in sorted_words if word.count == max_letter_count]
WORDS = ['this', 'is', 'ordereddict', 'an', 'elementary', 'test', 'example', 'hippopotamus']
res = most_repeated_word(WORDS)
for i in res:
print(f"{i.word}: '{i.letter}' {i.count} times")
# ordereddict: 'd' 3 times
# elementary: 'e' 3 times
# hippopotamus: 'p' 3 times