[#44310] プログラムに対して意図したとおりの文字列を渡す方法 — "Information Kanasansoft" <kanasansoft@...>

kanasanです。

9 messages 2007/12/05

[#44332] クラス:相互参照系の作成方法について質問です — "Saburoh Sakai" <sabroh@...>

はじめまして、さかいと申します。

12 messages 2007/12/11

[#44366] Rake改善プロジェクト — "Hajime Hoshi" <hajimehoshi@...>

東京大学修士 1 年の星一と申します。

14 messages 2007/12/19

[ruby-list:44353] Re: 配列のシャッフル

From: "Takehiro Nagai" <lukesilvia@...>
Date: 2007-12-18 01:36:45 UTC
List: ruby-list #44353
永井と申します。

>そこで,質問なのですが,
>何故,『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)<lukesilvia@gmail.com>
神奈川大学 理学部 情報科学科
http://d.hatena.ne.jp/LukeSilvia/


07/12/18 に 前原正英 Maehara Masahide <maehrm@miyazaki-c.ed.jp> さんは書きました:
>
> 前原と申します。
>
> 現在,『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)<maehrm@miyazaki-c.ed.jp>
> 宮崎県立佐土原高等学校/情報技術科
> http://www.miyazaki-c.ed.jp/sadowara-th/
> GPG Fingerprint: 17A6 8B1C 1186 1B45 41AE 5BBB CE42 E9EA 69A2 5844
>
>

In This Thread