From: Takehiro Nagai Date: 2007-12-18T10:36:45+09:00 Subject: [ruby-list:44353] Re: 配列のシャッフル ------=_Part_9402_33150540.1197941804950 Content-Type: text/plain; charset=ISO-2022-JP Content-Transfer-Encoding: 7bit Content-Disposition: inline 永井と申します。 >そこで,質問なのですが, >何故,『The Ruby Way』の方法では,配列の全要素をシャッフルできないのでしょうか? これは、collectと、slice!、lengthのレシーバが全てselfのためかと思います。 collectは、selfの長さ分処理を繰り返します。 しかし、下記のコードですと、collect内でslice!を使っているので、collectを一回繰り返す 度にselfの要素数が減ってしまいます。 -------------------------------- def randomize! result = collect { slice!(rand(length)) } replace result end ※slice!は取り出した要素がレシーバ取り除かれます irb(main):001:0> a = [1,2,3] => [1, 2, 3] irb(main):002:0> a.slice!(1) => 2 irb(main):003:0> a => [1, 3] -------------------------------- すると、3番目の要素を取り出した次のループは4回目であり、そのときのselfの長さは3なので、 4回目のループ処理が実行される前にループを抜けてしまいます。 同様に、要素が9個なら6回目、よって結果の配列の長さは5 要素が4個なら3回目、よっ結果の配列の長さは2となります。 これが、最初の例で要素が減ってしまう原因です。 対して下記の例では、collectのレシーバはselfですが、slice!、lengthのレシーバはarrです。 よって、collectはselfの長さ分の処理を繰り返し、無事シャッフルされます。 -------------------------------- class Array def shuffle arr = dup collect{ arr.slice!(rand(arr.length)) } end end -------------------------------- 参考になれば幸いです。 -------------------------------- 永井 健博(Nagai Takehiro) 神奈川大学 理学部 情報科学科 http://d.hatena.ne.jp/LukeSilvia/ 07/12/18 に 前原正英 Maehara Masahide さんは書きました: > > 前原と申します。 > > 現在,『The Ruby Way』を読んでいるのですが,その中で以下のような配列の > シャッフルについての記述があります。 > > =============================================================== > class Array > def randomize! > result = collect { slice!(rand(length)) } > replace result > end > > def randomize > arr = self.dup > arr.randomize! > arr > end > end > > a = [1, 2, 3, 4, 5] > p a.randomize! > =============================================================== > > 上記を実行すると,以下のようになり,配列の要素2つ分が表示されません。 > > =============================================================== > % ruby array_randomize.rb > [1, 4, 3] > % ruby -v > ruby 1.8.6 (2007-03-13 patchlevel 0) [i686-linux] > =============================================================== > > 『Ruby レシピブック 268の技』のP160には,以下のような例が示されており, > これだと配列をシャッフルできています。 > > =============================================================== > class Array > def shuffle > arr = dup > collect{ arr.slice!(rand(arr.length)) } > end > end > =============================================================== > > そこで,質問なのですが, > 何故,『The Ruby Way』の方法では,配列の全要素をシャッフルできないので > しょうか?アドバイスを頂ければ幸いです。 > -- > 前原 正英(Maehara Masahide) > 宮崎県立佐土原高等学校/情報技術科 > http://www.miyazaki-c.ed.jp/sadowara-th/ > GPG Fingerprint: 17A6 8B1C 1186 1B45 41AE 5BBB CE42 E9EA 69A2 5844 > > ------=_Part_9402_33150540.1197941804950--