ジョギング
- 嬉野の街を 45 分くらい
- 宿泊していたホテルから椎葉山荘 に登って, お茶畑を周りに見ながら走った
- 気持ち良かった
日課
- お休み
今日のるびぃ ~ REx - Ruby Examination にチャレンジ (36) ~
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)__ に適切な内容を選択して実行すると, [97, 112, 112, 108, 101]
と表示される. 期待した結果を得られるように正しい選択肢を選ぶ.
enum_char = Enumerator.new do |yielder| "apple".each_char do |chr| __(1)__ end end array = enum_char.map do |chr| chr.ord end p array
以下, irb にて確認.
irb(main):001:0> enum_char = Enumerator.new do |yielder| irb(main):002:1* "apple".each_char do |chr| irb(main):003:2* yielder << chr irb(main):004:2> end irb(main):005:1> end => #<Enumerator: #<Enumerator::Generator:0x00558ba63f9468>: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 => [97, 112, 112, 108, 101] irb(main):010:0> irb(main):011:0* p array [97, 112, 112, 108, 101] => [97, 112, 112, 108, 101]
以下, 解説より抜粋.
map
メソッドのブロックはEnumerator
オブジェクトをレシーバーとした場合Enumerator::Yielder
オブジェクトとなり, 設問では変数yielder
を指すEnumerator::Yielder
を評価するには,<<
を呼び出す
Enumerator クラスをも少し突っ込んで (ドキュメントを参考に)
Enumerator クラスとは
each
以外のメソッドにも Enumerable の機能を提供するためのラッパークラス- Enumerator を生成するには
Enumerator.new
あるいはObject#to_enum
,Object#enum_for
を利用する
そもそも Enumerable クラスとは
- 繰り返しを行なうクラスのための Mix-in
- このモジュールのメソッドは全て
each
を用いて定義されているので, インクルードするクラスにはeach
が定義されている必要がある
Enumerator.new について
new(obj, method = :each, *args) -> Enumerator
- オブジェクト obj について, each の代わりに method という 名前のメソッドを使って繰り返すオブジェクトを生成して返す
- args を指定すると, method の呼び出し時に渡される
irb(main):001:0> str = "xyz" irb(main):003:0* enum = Enumerator.new(str, :each_byte) (irb):3: warning: Enumerator.new without a block is deprecated; use Object#to_enum => #<Enumerator: "xyz":each_byte> irb(main):004:0> enum.class => Enumerator irb(main):007:0> enum.map {|b| '%02x' % b } => ["78", "79", "7a"]
new(size=nil) {|y| ... } -> Enumerator
- Enumerator オブジェクトを生成して返す
- 与えられたブロックは Enumerator::Yielder オブジェクトを引数 (以下の例では
y
が該当する) として実行される - 生成された Enumerator オブジェクトに対して
each
を呼ぶと, この生成時に指定されたブロック ((1..10).each{|i|...
) を実行し, Yielder オブジェクトに対して<<
メソッドが呼ばれるたびに,each
に渡されたブロックが繰り返される - new に渡されたブロックが終了した時点で each の繰り返しが終了し, このときのブロックの返り値が each の返り値となる
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:0x0055620e1400f8>:each> irb(main):006:0> enum.each{|i| p i } 5 10 => 1..10 irb(main):007:0> fib = Enumerator.new { |y| irb(main):008:1* a = b = 1 irb(main):009:1> loop { irb(main):010:2* y << a irb(main):011:2> a, b = b, a + b irb(main):012:2> } irb(main):013:1> } => #<Enumerator: #<Enumerator::Generator:0x0055620e0dbec8>:each> irb(main):014:0> p fib.take(10) [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
以下, Object#enum_for
や Object#to_enum
について.
Object#enum_for
や Object#to_enum
についても, Enumerator.new
と同様に Enumerator オブジェクトを返す. 以下, ドキュメントより引用.
irb(main):011:0* enum = str.enum_for(:each_byte) => #<Enumerator: "xyz":each_byte> irb(main):012:0> p(a = enum.map{|b| '%02x' % b }) ["78", "79", "7a"] => ["78", "79", "7a"] irb(main):013:0> enum = str.to_enum(:each_byte) => #<Enumerator: "xyz":each_byte> irb(main):014:0> p(a = enum.map{|b| '%02x' % b }) ["78", "79", "7a"] => ["78", "79", "7a"]
以下, ブロックを指定する場合.
irb(main):001:0> module Enumerable irb(main):002:1> def repeat(n) irb(main):003:2> raise ArgumentError, "#{n} is negative!" if n < 0 irb(main):004:2> unless block_given? irb(main):005:3> # __method__ はここでは :repeat irb(main):006:3* return enum_for(__method__, n) do # return to_enum(__method__, n) でも同義 irb(main):007:4* # size メソッドが nil でなければ size * n を返す。 irb(main):008:4* sz = size irb(main):009:4> sz * n if sz irb(main):010:4> end irb(main):011:3> end irb(main):012:2> each do |*val| irb(main):013:3* n.times { yield *val } irb(main):014:3> end irb(main):015:2> end irb(main):016:1> end => :repeat irb(main):017:0> %i[hello world].repeat(2) { |w| puts w } hello hello world world => [:hello, :world] irb(main):018:0> enum = (1..14).repeat(3) => #<Enumerator: 1..14:repeat(3)> irb(main):019:0> enum.first(4) => [1, 1, 1, 2] irb(main):020:0> enum.first(10) => [1, 1, 1, 2, 2, 2, 3, 3, 3, 4] irb(main):021:0> enum.size => 42
フムフム.