二十代は模索のときブログ」カテゴリーアーカイブ

reduce関数で階乗計算をしてみる

関数で遊んでばっかりだけど、これが最後かな。まだリスト内包表記もあるけど。
reduce関数は与えられた式とリストに対して、計算の結果と次の値をまた計算し、その結果と次の値をまた計算し…というのを繰り返してくれる関数。

前に階乗計算を

def factorial(x):
if x == 1:
return 1
else:
return x * factorial(x - 1)

と書いたけど、reduce関数を使えばわずか、

def factorial(x):
return reduce((lambda x,y: x * y),range(1,x+1))

で済んじゃう。速度的なメリットもあるというし、分かりづらいコードにならないのであれば、こっちを使いたくなるのがプログラマ根性ってやつかな。

実行結果は以下。

>>> factorial(1)
1
>>> factorial(2)
2
>>> factorial(3)
6
>>> map(factorial,[4,5,6,10])
[24, 120, 720, 3628800]

人生計画が足し算な人、逆算な人

LIGAYA REPORT:二十代や三十代の「使い方」

上の文章は少し大袈裟だとは思いますが、インキュベーション事業(起業支援事業)を行っている当社としても、二十代や三十代の「使い方」は非常に大切であると考えています。

「二十代」でググッたら引っかかった文章。どうやら大前研一氏の即戦力の磨き方 (PHPビジネス新書)に対する書評らしい。以下の文章が印象的だったのでちょっと引用。

「ゼネラリスト」と「スペシャリスト」の差は何かというと、人生計画を「足し算」で考えているか、「逆算」で考えているか、という違いが大きいと思います。
「スペシャリスト」は、人生を逆算して考えています。35歳までに独立すると決め、そのためには今は何をすべきかを常に考えています。そして実行に移しています。
「ゼネラリスト」は、人生を足し算で考えていますので、このまま行けば35歳で年収800万円かな? というような空想しか描けません。行動力もありません。

例えば三十台前半で「何がしかのスペシャリスト」になる為に、まず二十代は様々なことに真剣に取り組んでみる。二十代を「まずはやってみる」時期と規定しよう、というのが一応当ブログのテーマ。物理現象で例えてみると、二十代は「振幅」のすごく大きなグラフだけど、だんだんその振幅が小さくなってきて、三十台半ばくらいから一つの軸に収束していくという感じかな。この「振幅を最初は大きくしておこう」っていうのは結構ポイントだと思っている。引用した逆算理論は非常に正しいと思っているのだが、中にははじめから逆算しすぎていきなり振幅の小さなグラフになろうとする若者がいるのも事実。まずは色々と本気出して取り組んでみた方が、より自分がどこに収束すべきか見えてくるだろう、と僕は考えます。

ちなみに日本では「スペシャリスト」と言っても「社内のある業務のスペシャリスト」に向かってしまう人が多く、それはそれで重宝がられる人間なんだけど、ちょっと若人が描いているイメージとは違いますよね。これも振幅が大きな段階では経験しておいても悪くないだろうけど。

しかし話は逸れるが、大前氏は良くも悪くも変わらない人である。彼の著作を何冊か読めば気付くことだが、世間というか日本のビジネスパーソンに対してひたすら同じ事を言い続けている。氏のメッセージはビジネスパーソンであればすべからく吸収しておくべきだと思うが、内容もあまり変わらないし、僕は何冊か読んだ時点で一度氏の書籍からは距離を置いている。そろそろまた一冊読んでみようかな、と思ったりもするのだが、即戦力の磨き方 (PHPビジネス新書)はそれに適した内容だろうか。

filter関数で遊ぶ

Foundations of Python Network Programming

filter関数も非常に便利な関数だ。前にやったIPアドレス取得のプログラムを少し改造した関数を作り、IPアドレスをある個数以上持つホスト名を選び出すフィルタを作ってみよう。

以下のような関数countipaddrを作る。返り値はIPアドレスの個数。

import socket
def countipaddr(hostname):
try:
return len(socket.getaddrinfo(hostname,None))
except socket.gaierror:
return 0

実行結果。

>>> filter((lambda s:countipaddr(s) >= 3),['www.yahoo.co.jp','www.gogle.com','www.hatena.ne.jp','www.yahoe.co.jp','mixi.jp'])
['www.yahoo.co.jp', 'www.gogle.com', 'mixi.jp']
>>> filter((lambda s:countipaddr(s) >= 3),['www.yahoo.com','www.msn.com','www.cnet.com','www.amazon.com','www.goo.co.jp'])
['www.yahoo.com']

AmazonなんかはIPアドレスたくさん持ってないんですね(調べたら一つだった)。逆にmixiはたくさん持ってるな。

filter関数を使えば、前回やったエラトスセネスの篩のアルゴリズムもより簡素の形になるだろう。今度やってみるか。

IPアドレス取得プログラム

Foundations of Python Network Programming
前にJavaでも作ったけど、今度はPythonでIPアドレスの取得プログラムを作ってみる。要はDNSへの問い合わせ。標準入力から受け取ったホスト名称に該当するIPアドレスを返すようにする。

せっかくネットワークの本を買ったんだから、こういうのも作らないと。

ipaddrget.py

import socket
while(1):
name = raw_input()
if name == '':
break
try:
result = socket.getaddrinfo(name,None)
for item in result:
print item[4]
except socket.gaierror:
print "DNS coundn't find %s" % (name)

実行結果。

www.google.com
('66.102.7.147', 0)
('66.102.7.99', 0)
('66.102.7.104', 0)
www.yahoo.com
('66.94.230.48', 0)
('66.94.230.49', 0)
('66.94.230.50', 0)
('66.94.230.75', 0)
('66.94.230.32', 0)
('66.94.230.42', 0)
('66.94.230.44', 0)
('66.94.230.46', 0)
www.hatena.co.jp
('202.181.97.45', 0)
www.yahoe.co.jp
DNS coundn't find www.yahoe.co.jp

getaddrinfoはリストの形で結果を返す関数で、リストの四番目の要素がIPアドレスとポート番号のタプル。今回は実行時にポートを指定していないから0返って来ている模様。ホスト名称が見つからない場合には、socket.gaierrorが返されるから、それに関する処理も入れてみた。

まだ分からないことも多いんで、もう少し突っ込んで学ぶ必要あるな。

エラトスセネスの篩

初等整数論には題材が豊富だ。今度はエラトスセネスの篩をやってみよう。以下に引数を指定すると、2からその引数までの間にある素数を表示する関数、eratosthenesを作成する。

eratosthenes.py

def deletemultiples(pn,L):
for i in L:
if i != 0 and i != pn:
if i % pn == 0:
L[i-2] = 0
return L
def eratosthenes(n):
L = range(2,n+1)
for i in L:
if i != 0:
L = deletemultiples(i,L)
for i in L:
if i != 0:
print i,

実行結果。

>>> eratosthenes(10)
2 3 5 7
>>> eratosthenes(100)
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
>>> eratosthenes(1000)
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997

アルゴリズムはもっとやりようあるけど一応出来た。forループに使っているリストを、forループの中でいじれるのか心配だったけど、どうやらやってもいいみたい。助かった。

津田沼のフレンチレストラン

ホント実家の周りのレストランは混んでいる。どこも予約でいっぱいだったりする。なんであんな外食文化なんだあの辺りは。とりあえず対策として少し離れたところまで車で行ってみた。

本日はフレンチレストラン。

http://www.mamoruya.com/chezcomo/index.htm

値段はコースで3,900円〜6,800円程度だったはず。正直内容の割には高めの印象だったが、それでもオードブルに出た真鯛のカルパッチョなんてレベルは高かった。フォアグラは最近までフランスから輸入禁止だった影響か、味がイマイチ。車だったから飲めなかったけど、赤ワインにぴったり合いそうな牛肉の赤ワイン煮込みなんかも食べました。

まずまずかな。

高安秀樹「経済物理学の発見」

経済物理学の発見 (光文社新書)

経済物理学の発見 (光文社新書)

やばい。なんだこの本、滅茶苦茶面白かったぞ。久しぶりに味わったこの知的興奮。是非とも皆さんも味わいなされ。たったの760円、250ページ強ですから。

本書は経済現象(本書では主に為替の変動を扱っている)を物理学的手法による解明を試みる新しい分野、経済物理学(エコノフィジックス)について解説した本である。フラクタル、ベキ分布、カオス。物理学者の目から見れば、経済情報の中に物理現象と似た現象が頻繁に観察出来る。そしてある経済的な問題(例えばインフレとかバブルとか)に対する解法も、物理学的手法により導き出せる可能性がある。そういった「経済を研究している物理学者」のお話である。

個人的な話になってしまうが、「経済物理学」という言葉を初めて知ったときは嬉しかった。「人間の行動をマクロに見たときに、物理の法則に似たある決まった動きが見られるのではないか」という考えをずっと持っていたからだ。そのことについて考えるとき、大学で勉強した統計力学を思い出したものだが、その考え方があながち間違っていなかったこともこの本を読んで分かった。さらに経済学を学ぶと誰もが抱く「そんな上手いこといくんかいな」的なもやもや感を見事に祓ってくれる可能性のある学問であることもこの本を読めば分かる。今まで読んだ経済学の本とはすっきり度が違う。この感動を無くさないうちに、高安先生の他の書籍にも手を出したいところだ。

この分野のさらなる発展を望む。

スライシングで遊ぶ

スライシングも非常に便利。リストや文字列に対して使えます。文字列の処理なんかには重宝しそうです。

とりあえず使ってみましょう。

また標準出力から文字列を読み取り、受け取った文字列の8文字までを結果として返す関数と、9文字目以降を*でマスクして返す関数を作ってみる。

cutletters.py

def cutletters(s,x):
return s[:x]
def maskletters(s,x):
cutlength = len(s) - x
if cutlength > 0:
s = s[:x]
s = s + '*' * cutlength
return s
else:
return s
while(1):
s = raw_input()
if s == '':
break
print cutletters(s,8)
print maskletters(s,8)

実行すると以下のようになる。

C:\Python24>python.exe cutletters.py
Michael Jordan
result1 : Michael
result2 : Michael ******
abcdefghijklmnopqrstu
result1 : abcdefgh
result2 : abcdefgh*************
hatena
result1 : hatena
result2 : hatena

マスクの方はもう少しスマートな書き方があるのかも。

追記:

こうすればもっとスマートだ。うん。リスト万歳。

def maskletters(s,x):
L = list(s)
L[x:] = ['*'] * (len(s) - x)
return ''.join(L)

Map関数を使ってみよう

僕のプログラミング経験にはMap関数に値するものは出てこなかった。非常に便利な機能である。さっそく使ってみよう。

n個の中からx個を取り出すときの組み合わせを求める関数を以下のように定義する。

def factorial(x):
if x == 1:
return 1
else:
return x * factorial(x - 1)
def combination(x,n):
return factorial(n) / (factorial(n - x) * factorial(x))

map関数を用いて以下のように実行すると、5個から3個、8個から4個、10個から5個の計算結果をリストの形でいっぱつで返してもらうことが出来る。

>>> map(combination,[3,4,5],[5,8,10])
[10, 70, 252]

うーん便利。コード書く量大分減らせそう。