お題2:単語数カウント (Python Workshop the Edge 2007)
お題2:単語数カウント
英文のテキストファイルを読み込んで単語の出現数を数えるプログラムを作れ。
例えばテキストファイルの中身が「It's fine day, isn't it? Yes, it is!」ならばit'sが1回、fineが1回、dayが1回、isn'tが1回、itが2回、yesが1回、isが1回となるように数えてよい。
(isn'tにはisが含まれているな、とか、It'sの'sはisの省略形だな、などと判断するのはとてもむずかしいので)
余力があれば出現頻度の多い順に出力するプログラムも書け。
で、作ってみた。
#!/usr/bin/env python2.5
# -*- coding: utf-8 -*-
import re;
## wordCount
# 文字列を渡すと、英単語に分解して出現頻度を求める
# splitPattern = 区切り文字のパターン指定(それっぽいものを適当に並べただけ)
# text = 指定した区切り文字で受け取った文字列を分割し、リストを作成する
# words = {単語:出現数}の辞書
def wordCount(src):
splitPattern = re.compile(' |\t|\n|\r|\?|\!|\(|\)|\"|\.|\,');
text = splitPattern.split(src);
words = {};
#単語の出現回数を数える
for word in text:
#空の単語は無視する
if (word != ''):
if (word in words):#今までに出たことがあるなら出現回数に+1する
words[word] += 1;
else:#初めての単語なら新規作成
words[word] = 1;
return words;
## sort
# wordCountで作った辞書をソートする。
# wordCount専用だからいっそclassにまとめた方が良いかも…。
def sort(dict):
#出現回数、アルファベットの順にプリントしていく
for word, count in sorted(words.iteritems(), lambda x,y:(y[1] == x[1] and cmp(x[0].lower(), y[0].lower())) or y[1]-x[1]):
print word + ": " + str(count) + ",",
if (__name__ == "__main__"):
from sys import argv,exit;
if (len(argv) != 2):
print 'ファイル指定は一つまででお願いします。';
exit();
text = open(argv[1]).read();
words = wordCount(text);
print words;
sort(words);
うへぇ。
ソートの仕方が全くわかりませんでした。
lambda式とsortedが組合わさると、両方わからない私にとってはどんな魔法だって感じですよ。
sortedの第一引数で指定したリストから2つ取って来て第二引数に渡す。
戻り値が+だとそのままで-だと入れ替える?(頭が働かない…)
とりあえず呪文は暗記しておこうかね?
lambdaとかについて
これ(↓)を、
def sort(dict):
#出現回数、アルファベットの順にプリントしていく
for word, count in sorted(words.iteritems(), lambda x,y:(y[1] == x[1] and cmp(x[0].lower(), y[0].lower())) or y[1]-x[1]):
print word + ": " + str(count) + ",",
lambda式を使わない、かつ、もっと細かくて順を踏んで書くとこんな(↓)感じになるらしい。
def sort(dict):
sortedWords = sorted(words.iteritems(), cmp_custom);
for word, count in sortedWords:
print word + ": " + str(count) + ",",
def cmp_custom(x,y):
if (y[1] == x[1]):
return cmp(x[0].lower(), y[0].lower());
else:
return y[1]-x[1];
ソートで使う比較用の関数を新しく作り、sortedの第二引数でその関数を指定してあげる。
それで、ソート済みのリスト((ワード,出現回数)のタプルが入ったリスト。print sortedWordsで見てみると良くわかる?)が取得できる。
取得したリストをfor文でぶん回して出力すればOKらしい。
…それにしても、変数の命名にかなりの問題がある気がする。