Rubyで数学の問題に挑戦している人がいた。
よく考えればLLで変なプログラム書く人って初めて見た。
どうしてもPHPでWebアプリケーション書く人は見たことあるけど。
しかし、Rubyというと僕の印象はこればっかり。
(1..100).each do |i|
p i
end
何が言いたいかというとeachメソッド便利ですねということです。
まぁdoブロックの使い方とかはおもしろいですよね。
ただ、ブロックの終わりにいちいちend書くのめんどくさいとか。
まぁいろいろあるのだが、普段C#とかPerlでプログラム書くとき、
for(1..100) {} とまず打ってしまう、そして1文字戻って中身を書くと。
しかし、endで同じことをやると3文字も後退しないといけないなぁと…別に大した差ではないか。
まぁ人によっていろいろあるだろうが、この辺はお好きにどうぞ。
いろいろ見せてもらってたのだが、こんなことがあった。
1文字目、10文字目、…、100000文字目の文字を取り出したいと。
これを素直にやると大変ですね。
そこで僕は、これはクラス作ればいいですねと思ったわけだ。
というわけでささっとクラスを作ってみた。Rubyでクラス作るの初めて。
class Selectstring
attr_reader :len , :res;
def initialize()
@len=0
@select=[1,10,100,1000,10000,100000]
@res=[]
end
def append(str)
len0=@len+1
@len+=str.size
@select.each_with_index do |cur,i|
if len0<=cur and cur<=@len
res[i]=str[cur-len0]
end
end
end
end
Stringクラスのsizeプロパティ、lengthプロパティ、どっちも1.8ではバイト数を返すのね。
1.9ではlengthは文字数になるみたいだけど。
さて、それはともかく、Rubyの変数名の頭に付ける@はインスタンス変数の意味。
@@だとクラス変数。
なるほどこうやってローカル変数と区別してるのか…
あと、C#でいうプロパティはattr_reader, attr_writerで簡易に作ることができると。
自作もわりと簡単にできるらしいです。
each_with_indexというのは面白いですね。まぁPHPならfor($arr as $idx=>$cur){ }とかでできるけど。
1つ変数用意して、ループ内で毎度インクリメントすればいいこととはいえ、これは便利。
str[cur-len0]という操作だが、これは文字列の何番目かの文字の文字コードを取り出すものらしい。
文字コードなんですよ。
文字コードから文字に直すのはchrメソッドでできるのであらかじめやっておけばよかったなとか。
さて、これの使い方だが、
まぁ結論から言えば、123456789101112…という無限に続く数の
1,10,100,1000,10000,100000番目の数を取り出し、これの積を取ると。
というわけでさっきのクラスを使って問題を解く。
myss=Selectstring.new()
j=1
while myss.len<100000
myss.append(j.to_s)
j+=1
end
p myss.res.inject(1){ |last,cur| last*cur.chr.to_i }
まぁこんな感じ。ArrayのinjectメソッドでPerl 6の[*]演算子みたいなことをやってる。
injectは、前回の計算結果と今回の取り出した値を使ってなんか値作ってするやつ。
まぁもっとわかりやすい説明があると思うのでそれ探して。
ちなみにこの問題の答えは210となった。正解らしい。
まぁこんな風に割と使い捨てのクラスも作りやすいです。
Pythonのときも同じようなことをいってた気がする。
そういえばPerl 6ではオブジェクト指向のことがいろいろ変わるんだとか。
それによってクラスもかなり作りやすくなるはず。
また調べておこう。