keep_if を使ってみる (Ruby)
Ruby
Published: 2020-12-05

やったこと

keep_if を使ってみます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

調査

$ irb
irb(main):001:0> a = %w[a b c d]
irb(main):002:0> a.keep_if {|v| v == 'a' || v == 'd'}
=> ["a", "d"]

block のなかで false 判定の要素を削除します。

ちなみに Array#select! Array#filter! でも同じことが出来ます。

irb(main):004:0> a = %w[a b c d]
irb(main):005:0> a.select! {|v| v == 'a' || v == 'd'}
=> ["a", "d"]
irb(main):006:0> a
=> ["a", "d"]
...
irb(main):009:0> a = %w[a b c d]
irb(main):010:0> a.filter! {|v| v == 'a' || v == 'd'}
=> ["a", "d"]
irb(main):011:0> a
=> ["a", "d"]

少し深ぼってみます

  # Equivalent to Set#keep_if, but returns nil if no changes were
  # made. Returns an enumerator if no block is given.
  def select!(&block)
    block or return enum_for(__method__) { size }
    n = size
    keep_if(&block)
    self if size != n
  end

  # Equivalent to Set#select!
  alias filter! select!

削除対象があるかどうかで、違いがあるようですね。

irb(main):012:0> a = %w[a b c d]
irb(main):013:0> a.filter! {|v| true }
=> nil
irb(main):014:0> a = %w[a b c d]
irb(main):015:0> a.keep_if {|v| true }
=> ["a", "b", "c", "d"]

コメントにある通り、削除対象がない場合に nil を返すのか self を返すのかで挙動が違うことが分かりました。

参考