ようへいの日々精進XP

よかろうもん

2018 年 05 月 26 日(土)

ジョギング

  • 自宅→香椎宮香椎浜
  • 何気に足に負担がきているなーという感じ

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

奥さんと天神デート

天神で所用を済ませた後, ブラブラと博多まで夫婦で歩く. その途中で櫛田神社に立ち寄ってお参り.

hakatanomiryoku.com

初の櫛田神社だった.

博多駅の地下街にある焼肉屋さんで夕食. お腹一杯食べた.

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (10) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

Enumerator クラス

以下のプログラムの __(1)__ に適切なコードを入力して実行すると, [98, 97, 110, 97, 110, 97] と表示される. 期待した結果を得られるように正しい選択肢を選ぶ.

enum_char = Enumerator.new do |yielder|
  "banana".each_char do |chr|
    __(1)__
  end
end

array = enum_char.map do |chr|
  chr.ord
end

p array

yielder << chr

以下, irb による確認.

irb(main):001:0> enum_char = Enumerator.new do |yielder|
irb(main):002:1*   "banana".each_char do |chr|
irb(main):003:2*     yielder << chr
irb(main):004:2>   end
irb(main):005:1> end
=> #<Enumerator: #<Enumerator::Generator:0x0056404d2ee058>:each>
irb(main):006:0> 
irb(main):007:0* array = enum_char.map do |chr|
irb(main):008:1*   chr.ord
irb(main):009:1> end
=> [98, 97, 110, 97, 110, 97]
irb(main):010:0> 
irb(main):011:0* p array
[98, 97, 110, 97, 110, 97]
=> [98, 97, 110, 97, 110, 97]

以下, 解説より抜粋.

  • map メソッドのブロックは Enumerator オブジェクトをレシーバーとした場合に, Enumerator::Yielder オブジェクトとなり, 設問上のプログラムでは変数 yielder を指す
  • Enumerator::Yielder を評価するには, << を呼び出す

フムフム.

ちょっと理解に苦しんだので, コードを自分なり解析していくことにする.

  • Enumerator クラスについて

ドキュメントより引用.

each 以外のメソッドにも Enumerable の機能を提供するためのラッパークラスです。

Enumerator.new することで, Enumerable なオブジェクトを生成することが出来るという理解. また, Enumerator を生成する場合,

  • Enumerator.new
  • Object#to_enum
  • Object#enum_for

を利用する.

  • そして, Enumerator.new について

さらに, ドキュメントより引用.

Enumerator オブジェクトを生成して返します。与えられたブロックは Enumerator::Yielder オブジェクトを 引数として実行されます。 生成された Enumerator オブジェクトに対して each を呼ぶと、この生成時に指定されたブロックを 実行し、Yielder オブジェクトに対して << メソッドが呼ばれるたびに、 each に渡されたブロックが繰り返されます。 new に渡されたブロックが終了した時点で each の繰り返しが終わります。 このときのブロックの返り値が each の返り値となります。

以下, サンプルコード.

enum = Enumerator.new{|y|
  (1..10).each{|i|
    y << i if i % 5 == 0
  }
}
enum.each{|i| p i }

上記のサンプルを irb で実行する.

irb(main):001:0> enum = Enumerator.new{|y|
irb(main):002:1*   (1..10).each{|i|
irb(main):003:2*     y << i if i % 5 == 0
irb(main):004:2>   }
irb(main):005:1> }
=> #<Enumerator: #<Enumerator::Generator:0x0055b00eac7a60>:each>
irb(main):006:0> enum.each{|i| p i }
5
10
=> 1..10
  • 上記のサンプルだと, y が Enumerator::Yielder オブジェクトになる
  • Enumerator::Yielder オブジェクトに対して, << を呼ぶと {|i| p i } が実行される

という理解しか今のところは出来ない...

他にも Enumerator の実行例.

irb(main):003:0* enum = Enumerator.new(str, :scan, /\w+/)
(irb):3: warning: Enumerator.new without a block is deprecated; use Object#to_enum
=> #<Enumerator: "Yet Another Ruby Hacker":scan(/\w+/)>
irb(main):004:0> enum.each {|word| p word }
"Yet"
"Another"
"Ruby"
"Hacker"
=> "Yet Another Ruby Hacker"
irb(main):005:0> str.scan(/\w+/) {|word| p word }
"Yet"
"Another"
"Ruby"
"Hacker"
=> "Yet Another Ruby Hacker"
irb(main):006:0> "Hello, world!".scan(/\w+/)
=> ["Hello", "world"]
irb(main):007:0> "Hello, world!".to_enum(:scan, /\w+/).to_a
=> ["Hello", "world"]
irb(main):008:0> "Hello, world!".to_enum(:scan).each(/\w+/).to_a
=> ["Hello", "world"]

フムフム...