map(またはcollect)はブロックの戻り値を集めた配列を生成してくれる便利なメソッドです。
しかし、ブロックの途中でnextを使用すると意図せずnilが入ってしまう場合があるため、気をつける必要があります。
例えば以下のような数字の配列から偶数を取り出すメソッドを作成したとします。
# 引数で渡した配列から偶数だけ取り出したい
def getEvenNumber(numArray)
numArray.map do |num|
next if num % 2 != 0
num
end
end
上記メソッドに対し、1〜5の整数の配列を引数に与えてみます。
この場合、2と4の配列が返ってくることが期待する結果です。
getEvenNumber([1,2,3,4,5])
=> [nil, 2, nil, 4, nil]
2と4は期待通り返ってきたのですが、それ以外の要素がnilになってしまいました。
mapは配列の各要素に対して処理を行い、その結果を配列にして返却するため、もとの配列の数と生成された配列の要素数は等しくなります。そのため、途中でnextを入れて処理をスキップしたつもりでも、結果の配列にnilがセットされてしまうのです。
そこで、もしnilを配列に入れたくないのであれば、以下のようにmapした後にcompactを行うことで回避することができます。
def getEvenNumber(numArray)
numArray.map do |num|
next if num % 2 != 0
num
end.compact
end
getEvenNumber([1,2,3,4,5])
=> [2, 4]
mapとcompactを使用しない別の方法としては、selectやrejectを使うのもありです。
もちろん使えない、使わない方が良いケースもあるので状況に応じてになりますが、今回のケースではこちらの方がシンプルですね。
# selectを使う
def getEvenNumber(numArray)
numArray.select do |num|
num % 2 == 0
end
end
# rejectを使う
def getEvenNumber(numArray)
numArray.reject do |num|
num % 2 != 0
end
end
意図しないnilが含まれているとバグにも繋がるため、mapを使用する際はぜひ意識しておくと良いと思います。