ようへいの日々精進XP

よかろうもん

2018 年 06 月 10 日 (日)

ジョギング

  • 自宅→香椎神宮香椎浜 x 1 周
  • 引き続き, 右足 (右腰から右足全体) にかけて痛み

日課

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

リゾート温泉ホテルごっこ

奥さんの体調がイマイチだったので, 自宅をリゾート温泉ホテルに見立てて, お風呂にバスクリンのお湯を張って半身浴をさせたり, 小洒落た朝ごはんを作って食べさせたりした. 今は焦らず, ゆっくりのんびり元気になって欲しい.

頭痛

  • 夜になって肩がとても張って, 右側の頭痛が激しい

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

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

以下のコードの実行結果と同じ結果となるような実装を選択しから選ぶ.

# コード
class Array
  def succ_each(step = 1)
    return enum_for(:succ_each, step) unless block_given?

    each do |int|
      yield int + step
    end
  end
end

p [98, 99, 100].succ_each(2).map {|succ_chr| succ_chr.chr}

[101, 102, 103].succ_each(5) do |succ_chr|
  p succ_chr.chr
end

# 実行結果
["d", "e", "f"]
"j"
"k"
"l"

まずは, コードを irb で動作確認.

...
irb(main):011:0* p [98, 99, 100].succ_each(2).map {|succ_chr| succ_chr.chr}
["d", "e", "f"]
=> ["d", "e", "f"]
irb(main):012:0> 
irb(main):013:0* [101, 102, 103].succ_each(5) do |succ_chr|
irb(main):014:1*   p succ_chr.chr
irb(main):015:1> end
"j"
"k"
"l"
=> [101, 102, 103]

以下, 解答.

# 解答 1
class Array
  def succ_each(step = 1)
    return to_enum(:succ_each, step) unless block_given?

    each do |int|
      yield int + step
    end
  end
end

p [98, 99, 100].succ_each(2).map {|succ_chr| succ_chr.chr}
[101, 102, 103].succ_each(5) do |succ_chr|
  p succ_chr.chr
end

# 解答 2
class Array
  def succ_each(step = 1)
    unless block_given?
      Enumerator.new do |yielder|
        each do |int|
          yielder << int + step
        end
      end
    else
      each do |int|
        yield int + step
      end
    end
  end
end

p [98, 99, 100].succ_each(2).map {|succ_chr| succ_chr.chr}
[101, 102, 103].succ_each(5) do |succ_chr|
  p succ_chr.chr
end

以下, 解説より抜粋.

  • ブロックを渡す場合と, チェーンを行う場合の両方を考慮する必要がある
  • チェーンを行う場合は Enumerator オブジェクトを作成する必要がある
  • Enumerator オブジェクトの作成に必要なメソッドは enum_forto_enum がある
  • 設問のコードでは enum_for を使っているので, 選択肢のうち to_enum を使っている選択肢が答えの一つになる
  • 尚, to_enum は引数にメソッド名とそのメソッドに必要な引数を指定する必要がある為, 設問のコードでは, succ_each メソッドに引数 2 を渡している為, Enumerator オブジェクトを作成するときに必要になる
  • Enumerator オブジェクトは new メソッドで作成することが出来る為, 以下のように実装することも出来る
class Array
  def succ_each(step = 1)
    unless block_given? # ブロックが無い場合は、オブジェクトを作成
      Enumerator.new do |yielder|
        each do |int|
          yielder << int + step
        end
      end
    else # ブロックがある場合の実装
      each do |int|
        yield int + step
      end
    end
  end
end
  • チェーンした先で渡されたブロックを評価するためには Enumerator::Yielder のオブジェクトを利用する
  • オブジェクトに対して, << を実行することでブロック内で評価した結果を受け取ることが出来る

フムフム.