2012年5月31日木曜日

プロジェクトオイラー Problem17_2

前回のproblem17のソースコードを見て、61mgさんから改良意見をいただきました。
変換した英単語を集める最後のループでカラ回りする記述が冗長とのことで、これを無くしてみました。


私の解答例は以下です。
-----

D1 = {0:"", 1:"one", 2:"two", 3:"three", 4:"four", 
	5:"five", 6:"six", 7:"seven", 8:"eight", 9:"nine"}
	
D10 = {10:"ten", 11:"eleven", 12:"twelve", 13:"thirteen", 
	14:"fourteen", 15:"fifteen", 16:"sixteen", 17:"seventeen", 
	18:"eighteen", 19:"nineteen"}
	
D20 = {20:"twenty", 30:"thirty", 40:"forty", 50:"fifty", 
	60:"sixty", 70:"seventy", 80:"eighty", 90:"ninety"}
	
def f(n):
	t = 0
	for i in xrange(1, n+1):
		L, M = [int(j) for j in str(i).rjust(4, "0")], []
		if L[-4]: M += [D1[i//1000], "thousand"]
		s = i%100
		if L[-3]:
			M += [D1.get(L[-3], ""), "hundred"]
			if s: M += ["and"]
		if s<10: M += [D1.get(s, "")]
		elif s<20: M += [D10.get(s, "")]
		else: M += [D20.get(L[-2]*10, ""), D1.get(L[-1], "")]
		t += sum([len(s.replace(" ","")) for s in M])
	return t
	
print f(1000)
-----

・辞書D1に1桁の数字の部品の英単語を設定しました。同様に、
辞書D10に10代の数字(10~19)、辞書D20に20以上の数字を設定しました。
100と1000は処理中に直書きしています。

・L, M = [int(j) for j in str(i).rjust(4, "0")], []
リストLに変換元の数字を、左0埋めで4桁にしてから1桁ずつを要素に設定します。
リストMは英単語を設定するので初期化しておきます。

・文字列.rjust(桁数, 埋め文字)
文字列を右詰めして指定桁数にします。あいた部分は埋め文字で埋めます。
ここでは、例えば以下のようになります。"1" → "0001"

・if L[-4]: M += [D1[i//1000], "thousand"]
下から4つ目は、千の位の値です。
これが0以外(論理的にTrue)のとき、例えば["one", "thousand"]のように設定します。

・if L[-3]:
   M += [D1.get(L[-3], ""), "hundred"]
   if s: M += ["and"]
下から3つ目は、百の位の値です。
これが0以外(論理的にTrue)のとき、例えば["one", "hundred"]のように設定します。
また、sは100で割った余りで、これが0以外なら"and"も設定します。

・if s<10: M += [D1.get(s, "")]
elif s<20: M += [D10.get(s, "")]
else: M += [D20.get(L[-2]*10, ""), D1.get(L[-1], "")]
下2桁の処理です。
sは100で割った余りで、これが10未満なら1桁、さらに20未満なら10代、その他は20以上の数字と1桁、といった組合せで英単語に変換します。

・t += sum([len(s.replace(" ","")) for s in M])
ここまで組み立ててきた英単語について、replace関数で半角空白を削除し、len関数で文字数を数え、sum関数で合計を取ります。


解答はこのすぐ下の行です。文字の色を白にしてます。選択状態にすると見えます。
21124



(追記)
・20120715
 ソースコード部分にSyntaxHighlighterを導入。

0 件のコメント:

コメントを投稿