search
LoginSignup
0
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

rubyのArray#compact!でnilを返させない

はじめに

rubyのArrayにはcompactと呼ばれる配列中のnilを消すメソッドが定義されていますが
nilのある無いにかかわらず配列に対してのcompactは「nilの無い配列」が返ります
しかしながら破壊的メソッドであるcompact!では
「nilのある配列」に対してのcompact!は「nilの無い配列」が返りますが
「nilの無い配列」に対してのcompact!は「nil」が返ります

前回からの変更が無いときは例外を出す見たいな時は便利ですが
統一性が無いので思わぬ動作を引き起こしかねない気もします
ってことでこの記事では専用の関数を作ります

(訂正)

compactが統一性がない」という記述になってましたが
統一性がないのは「compact!」です
ご指摘ありがとうございました

実例

compact1.rb
a=[60,21,nil,'foo',nil,0,'']
p a.compact!
p a.compact!
p a
実行結果
[60, 21, "foo", 0, ""]
nil
[60, 21, "foo", 0, ""]

このように気持ち悪い結果となります
そこでcompact2を定義してみました

compact2.rb
class Array
  def compact2!
    delete_if{|item| item.nil?}
  end
end

a=[60,21,nil,'foo',nil,0,'']
p a.compact2!
p a.compact2!
p a
実行結果
[60, 21, "foo", 0, ""]
[60, 21, "foo", 0, ""]
[60, 21, "foo", 0, ""]

いい感じですね
ついでなので空文字列も消しちゃいましょう

compact2b.rb
class Array
  def compact2!
    delete_if{|item| item.nil? || item==''}
  end
end

a=[60,21,nil,'foo',nil,0,'']
p a.compact2!
p a.compact2!
p a
実行結果
[60, 21, "foo", 0]
[60, 21, "foo", 0]
[60, 21, "foo", 0]

消えたことは消えたのですがdelete_ifの書き方が少し気持ち悪い気もします
blank?かempty?が使えればもっとうまく書けそうですが
文字列にしか使えない(Undefined Method Error)なので仕方なさそうです
(個人的には,正規表現によるフィルタなど,拡張しやすい形なので,それはそれでいいのではないかと思っています)

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
What you can do with signing up
0
Help us understand the problem. What are the problem?