tap の「使え方」
tap に渡すブロックで break をするとその break が tap の返り値を決定する。例えば、true.tap { break false } は false になる。
さて、以下の関数は、数当てゲームのヌメロンでプレーヤーの推測と答えを比較して、イート数(位置も数もあっている)とバイト数(数はあっているが位置が違う)を返すものだ。
def judge ans, try eat = ans.zip(try).count{|a,b| a==b} [eat, (ans & try).size - eat] end judge [1,2,3], [1,3,4] # => [1,1]
ここでこの eat という変数は、式の意味を説明することで、コードを人間にとって理解しやすくしているだけではなくて、計算量の制御のために必要なものだ。
関数を強引に1つの式で書くとイートの式が重複してしまい、同じ計算が2度行われてしまう。
def judge ans, try [ans.zip(try).count{|a,b| a==b}, (ans & try).size - ans.zip(try).count{|a,b| a==b}] end
これは望ましくない。ところが、あなたは宗教的の理由で代入文を書くことができない。
心配はない。その場合でも tap と break を使えば以下のように書ける。
def judge ans, try ans.zip(try).count{|a,b| a==b}.tap do |eat| break [eat, (ans & try).size - eat] end end
これであなたのコードは効率的な上に清浄だ。