ようへいの日々精進XP

よかろうもん

2018 年 06 月 02 日 (土)

ジョギング

日課

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

のんびりした休日

  • お昼ごはん食べて, 気付いたら昼寝してしまっていた
  • 夕飯食べて, ダラダラしてたら探偵ナイトスクープが始まって, 夫婦ふたりでお腹を抱えて笑った

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

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)

Enumerable, Enumerator

次のプログラムを実行するために __(1)__ に適切なメソッドをすべて選ぶ.

class IPAddr
  include Enumerable

  def initialize(ip_addr)
    @ip_addr = ip_addr
  end

  def each
    return __(1)__ unless block_given?

    @ip_addr.split('.').each do |octet|
      yield octet
    end
  end
end

addr = IPAddr.new("192.10.20.30")
enum = addr.each

p enum.next # 192と表示される
p enum.next # 10と表示される
p enum.next # 20と表示される
p enum.next # 30と表示される

to_enum enum_for

以下, irb による確認.

irb(main):001:0> class IPAddr
irb(main):002:1>   include Enumerable
irb(main):003:1> 
irb(main):004:1*   def initialize(ip_addr)
irb(main):005:2>     @ip_addr = ip_addr
irb(main):006:2>   end
irb(main):007:1> 
irb(main):008:1*   def each
irb(main):009:2>     return to_enum unless block_given?
irb(main):010:2> 
irb(main):011:2*     @ip_addr.split('.').each do |octet|
irb(main):012:3*       yield octet
irb(main):013:3>     end
irb(main):014:2>   end
irb(main):015:1> end
=> :each
irb(main):016:0> 
irb(main):017:0* addr = IPAddr.new("192.10.20.30")
=> #<IPAddr:0x00556232b19970 @ip_addr="192.10.20.30">
irb(main):018:0> enum = addr.each
=> #<Enumerator: #<IPAddr:0x00556232b19970 @ip_addr="192.10.20.30">:each>
irb(main):019:0> p enum.next
"192"
=> "192"
irb(main):020:0> p enum.next
"10"
=> "10"
irb(main):021:0> p enum.next
"20"
=> "20"
irb(main):022:0> p enum.next
"30"
=> "30"

irb(main):001:0> class IPAddr
irb(main):002:1>   include Enumerable
irb(main):003:1> 
irb(main):004:1*   def initialize(ip_addr)
irb(main):005:2>     @ip_addr = ip_addr
irb(main):006:2>   end
irb(main):007:1> 
irb(main):008:1*   def each
irb(main):009:2>     return enum_for unless block_given?
irb(main):010:2> 
irb(main):011:2*     @ip_addr.split('.').each do |octet|
irb(main):012:3*       yield octet
irb(main):013:3>     end
irb(main):014:2>   end
irb(main):015:1> end
=> :each
irb(main):016:0> 
irb(main):017:0* addr = IPAddr.new("192.10.20.30")
=> #<IPAddr:0x0055a4d08957e0 @ip_addr="192.10.20.30">
irb(main):018:0> enum = addr.each
=> #<Enumerator: #<IPAddr:0x0055a4d08957e0 @ip_addr="192.10.20.30">:each>
irb(main):019:0> p enum.next
"192"
=> "192"
irb(main):020:0> p enum.next
"10"
=> "10"
irb(main):021:0> p enum.next
"20"
=> "20"
irb(main):022:0> p enum.next
"30"
=> "30"

以下, 解説より抜粋.

  • Enumerable をインクルードした場合は, each メソッドを実装する必要がある
  • ブロックが渡されない場合でも, Enumerator オブジェクトを返すようにして外部イテレータとしても使えるようにする
  • Enumerator オブジェクトを作成するメソッドは enum_for, または to_enum を利用する

Integer#times

以下のコードを実行するとどうなるか.

10.times{|d| print d < 2...d > 5 ? "O" : "X" }

以下, irb で確認.

irb(main):021:0> 10.times{|d| print d < 2...d > 5 ? "O" : "X" }
OOOOOOOXXX=> 10

ホー.

以下, 解説より抜粋.

  • Integer#times0 から self - 1 までの数値を順番にブロックに渡すメソッド
  • 設問では, ブロックに 0 から 9 が渡される

以下は Integer#times の利用例.

irb(main):001:0> 3.times { puts "Hello, World!" }
Hello, World!
Hello, World!
Hello, World!
=> 3
irb(main):002:0> 0.times { puts "Hello, World!" }
=> 0
irb(main):003:0> 5.times {|n| print n }
01234=> 5
  • d < 2...d > 5 は, 条件式に範囲式の合わせ技

これは何だ...ということで, ドキュメントより引用.

条件式として範囲式が用いられた場合には、状態を持つ sed や awk 由来の 特殊な条件式として振る舞います。

「..」の場合:

1. 初期状態では式1だけを評価し、式1が真を返すまでは false を返します。
2. 式1が真を返すと true を返します。式2が真なら初期状態に戻ります。
3. この後は式2だけを評価し、式2が真を返すまで true を返します。
4. 式2が真を返すと true を返したあと、初期状態に戻ります。

「...」の場合:

1. 初期状態では式1だけを評価し、式1が真を返すまでは false を返します。
2. 式1が真を返すと true を返します。
3. この後は式2だけを評価し、式2が真を返すまで true を返します。
4. 式2が真を返すと true を返したあと、初期状態に戻ります。

以下, サンプル.

irb(main):001:0> 5.times{|n|
irb(main):002:1*   if (n==2)..(n==3)
irb(main):003:2>     p n
irb(main):004:2>   end
irb(main):005:1> }
2
3
=> 5
irb(main):006:0> 5.times{|n|
irb(main):007:1*   if (n==2)...(n==3)
irb(main):008:2>     p n
irb(main):009:2>   end
irb(main):010:1> }
2
3
=> 5
irb(main):011:0> 5.times{|n|
irb(main):012:1*   if (n==2)..(n==2)
irb(main):013:2>     p n
irb(main):014:2>   end
irb(main):015:1> }
2
=> 5
irb(main):016:0> 5.times{|n|
irb(main):017:1*   if (n==2)...(n==2)
irb(main):018:2>     p n
irb(main):019:2>   end
irb(main):020:1> }
2
3
4
=> 5

ムムム.