算数にチャレンジしてみた
算数にチャレンジ! 第624回問題(11月20日〜 11月26日)
1〜512の数の書かれたカードが1枚ずつ、左から小さい順に、「1,2,3,4,・・・,511,512」と並んでいます。いま、次のような作業を行うことにします。
ア. 前から奇数番目のカードをすべて取り除く
イ. 前から偶数番目のカードをすべて取り除くまず、この作業を、ア→イ→ア→イ→・・・の順に、カードが残り1枚になるまで繰り返して行うことにします。
このとき、最後に残るカードに書かれた数字を答えてください。
http://www.sansu.org/
やってみた。*1
>ruby -v ruby 1.8.7 (2008-08-11 patchlevel 72) [i386-mswin32]
module Enumerable def delete_odd delete_modulo2 0 end def delete_even delete_modulo2 1 end def delete_modulo2 modulo [].tap do |result| each.with_index do |value, index| result << value unless index%2 == modulo end end end end
tapかわいいよtap。ということで、Enumerableモジュールにこんな感じでメソッドを追加して、
※remove_oddとremove_evenは今回使いませんが。
values = (1..512) [0, 1].cycle do |modulo| values = values.delete_modulo2 modulo break if values.size == 1 end p values.first #=> 342
こんな感じでサックリと……ってなんかキモいな。
「偶数番目を削除」メソッドの実装が「奇数番目を抽出」になってるからか……何か気になるけどスルーで。
本来ならばwith_indexなdelete_ifを使いたいんだけど、with_indexすると結果が値とindexの配列の配列になっちゃうから自作するはめに。HashのEnumerable系メソッドもそうだけど、結果は同じ形式にして欲しいところ。
※typoを修正。
追記 Enumerable#group_byを使った方法
ruby-listを見ていたらEnumerable#group_byなんて面白げなメソッドを発見したので修正してみた。
module Enumerable def delete_modulo2 modulo group_by.with_index{ |value, index| index%2 }[1-modulo] end end
実行速度のことはよくわかんないけど、とにかくコードがシンプルになった。これはうれしい。
さらに追記 Enumerable#selectを使った方法
よく考えると、delete_ifってArrayのメソッドだからwith_indexしたら配列になっちゃってたのか。
単純にselectにするのが一番自然だった。
module Enumerable def delete_modulo2 modulo select.with_index{ |value, index| index%2 == 1-modulo } end end
*1:n番目の問題ってリソースが決まってるんだからパーマリンクが欲しいなぁ。たぶんhttp://www.sansu.org/used-html/index624.htmlだけど今のところ空ページだわ。