50
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Ruby】mapの途中でnextを使用するとnilが入ってしまう罠

Posted at

map(またはcollect)はブロックの戻り値を集めた配列を生成してくれる便利なメソッドです。
しかし、ブロックの途中でnextを使用すると意図せずnilが入ってしまう場合があるため、気をつける必要があります。

例えば以下のような数字の配列から偶数を取り出すメソッドを作成したとします。

qiita.rb
# 引数で渡した配列から偶数だけ取り出したい
def getEvenNumber(numArray)
  numArray.map do |num|
    next if num % 2 != 0
    num
  end
end

上記メソッドに対し、1〜5の整数の配列を引数に与えてみます。
この場合、2と4の配列が返ってくることが期待する結果です。

qiita.rb
getEvenNumber([1,2,3,4,5])
=> [nil, 2, nil, 4, nil]

2と4は期待通り返ってきたのですが、それ以外の要素がnilになってしまいました。
mapは配列の各要素に対して処理を行い、その結果を配列にして返却するため、もとの配列の数と生成された配列の要素数は等しくなります。そのため、途中でnextを入れて処理をスキップしたつもりでも、結果の配列にnilがセットされてしまうのです。

そこで、もしnilを配列に入れたくないのであれば、以下のようにmapした後にcompactを行うことで回避することができます。

qiita.rb
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を使うのもありです。
もちろん使えない、使わない方が良いケースもあるので状況に応じてになりますが、今回のケースではこちらの方がシンプルですね。

qiita.rb
# 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を使用する際はぜひ意識しておくと良いと思います。

50
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
50
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?