reverseと,ついでに素数
iPod shuffleをオートフィルしている間に,軽く更新.弟が今日,C言語で配列を逆順にする,ってのをやってたので,それをRubyでやってみるかと.あと,素数求める続き.
まぁ正直RubyにはArray.reverseというのがあるので必要ないけど,これは練習なんですよ.
class Array def myreverse1 (0 .. (self.size / 2)).each{ |i| self[i] , self[self.size - i - 1] = self[self.size - i - 1] , self[i] } end end
うわ,ツマンネェ.
さっきのは破壊的だったけど,今度は破壊的でないものを.
class Array def myreverse2 rev = [] self.each{|e| rev = [e] + rev } rev end end
まぁなんとも他愛もない感じで.
ついでに再起しとくか.
class Array def myreverse3 rev = [] xs = self.dup reverse = lambda{ return rev if xs.empty? rev << xs.pop reverse[xs] } reverse[xs] end end
実行結果は割愛.
そうそう,これを書いてる時に,reject!というメソッドを見つけたのですが,これを適用してエラトステネスの篩を書いてみます.
def primes(n) prime = (2 .. n).to_a prime.each{|e| next if e == nil break if (n / e) < 2 (2 .. (n / e)).each{|x| prime[(e * x) - 2] = nil } } prime.reject!{|y| y == nil} end prime = primes(1000000) p prime.last p prime.length
なんかもう鬼の様に早くなった.
$ time ruby prime.rb 999983 78498 real 0m8.736s user 0m8.352s sys 0m0.110s
追記
ぶっちゃけdelete nilの方が可読性あるよな,ってベットの中で考えてると寝付けなかったのでやってみたのですが,
prime.delete nil
だと返り値はnilで,primeじゃないので,これを関数の返り値にはできない.だからprimeを返り値にしようとすると,
prime.delete nil prime
と一行長くなってしまう.その点,reject!なら,返り値がブロックで評価された要素が削除された配列なので,
prime.reject!{|e| e == nil}
で良い事になる.しかし,破壊的なreject!である必要はなく,rejectでも削除された配列が返るので,普通にrejectで良いか.実行時間も変わんなかったし.んじゃ,
prime.reject{|e| e == n}
でいいや.
破壊的じゃない場合って,返り値は新しいメモリなんかな.てか関数の返り値自体,新しいメモリなんか?あ,ガベージコレクションがあるからメモリ云々は気にしちゃ駄目ですか.