Array#zip

久しぶりのプログラミングに関する記事です。

Array#zipについて

表記はこんな感じでいいんですかね、よくわからないんですが・・・

まぁ、配列クラスのzipメソッドの話です。

zipメソッドはレシーバと引数から渡された配列の要素を1つずつ取り出して、そのたびにブロックを起動する。引数は1つでもそれ以上でも構わない。

らしいです。

実際にどんなかんじか、サンプルプログラムを見ながら、考えていこうと思います。

# encoding:utf-8

ary1 = [1,2,3,4,5]
ary2 = [10,20,30,40,50]
ary3 = [100,200,300,400,500]

result = []
ary1.zip(ary2,ary3) do |a,b,c|
        result << a + b + c
end
p result

#=> [111, 222, 333, 444, 555]

ary1,ary2,ary3のそれぞれの先頭から1つずつを取り出して、
足したものを空の配列resultにいれていき、ary1の要素数だけ繰り返したら、
resultを表示するというプログラムです。

ここまでは理解できたんですけど、ary1,ary2,ary3の要素数を変えたら、エラーが出て、なんでだろうって思ったので、まとめておきます。

# encoding:utf-8

ary1 = [1,2,3,4,5]
ary2 = [10,20,30,40]
ary3 = [100,200,300,400]

result = []
ary1.zip(ary2,ary3) do |a,b,c|
        result << a + b + c
end
p result

#=> sum_with_zip.rb:9:in `+': nil can't be coerced into Fixnum (TypeError)
#        from sum_with_zip.rb:9:in `block in <main>'
#        from sum_with_zip.rb:8:in `zip'
#        from sum_with_zip.rb:8:in `<main>'

エラーが出ました。

このプログラムの名前は、sum_with_zip.rbにしています。

ary1の要素数のほうを、ary2,ary3の要素数より大きくしました。

僕は、

#=> [111, 222, 333, 444, 5]

って結果になると期待してました。

結果はエラーだったので、色々とzipメソッドについて調べてたんですけど、
わからない・・・

わからなかったので、実行を追っていこうと思います。

ary1の要素数は5なので、このブロックは5回繰り返されます。

そして、その5回目の繰り返しが問題なんじゃないかと思いました。

ary1[4]には 5 が入っています。

しかし、ary2[4],ary3[4]には何も入っていません。

つまり、nilです。

だから、result[4]に 5 + nil + nil の結果を入れることになるんですが、

これがおかしいのでは・・・っと予想を。

irbでちょこちょこって色々と実行してみたら、

数値クラスとの足し算の時は
TypeError: nil can't be coerced into Fixnum

nil + nilの時は
NoMethodError: undefined method `+' for nil:NilClass

っていうエラーが出てきました。

nilと数値クラスの演算はできないみたいですね。

それとnilクラスに、+ってメソッドがないみたいなので、演算できないよってことですかね。

つまり、ary1の要素数のほうが大きい時にエラーが出るのは
zipメソッド自体の問題じゃなくて、
nilによるものってことですね。

今回のエラーを見て、
zipメソッドとか複数の配列に並行してアクセスするメソッドは、
ブロックの中をみて、nilの演算がでてこないかとかもちゃんと考えないといけないなって思いました。

なんだか、gdgdですが、これは終わりにします。

間違っているところがあったら、指摘していただけたら嬉しいです。

なお、サンプルプログラムやzipメソッドの説明は、
たのしいRuby第3版から引用させていただきました。