Ruby_Array_34

この記事は、以下のドキュメントを改変(自分なりに整理)して利用しています。

class Array (Ruby 3.1 リファレンスマニュアル)

インスタンスメソッド

keep_if {|item| ... } -> self
keep_if -> Enumerator
  • ブロックがfalseを返した要素を削除する
  • Array#select!と同様に自身を上書きするが、削除する要素がなかった場合には修正を行わない
  • ブロックが与えられなかった場合、自身とkeep_ifから生成したEnumeratorオブジェクトを返す
irb(main):001:0] arr = %w[a b c d e]
=> ["a", "b", "c", "d", "e"]

irb(main):003:0> arr.keep_if {|s|s =~ /[ace]/ }
=> ["a", "c", "e"]

irb(main):004:0> arr
=> ["a", "c", "e"]
irb(main):001:0> arr = %w[a b c d e]
=> ["a", "b", "c", "d", "e"]

irb(main):002:0> arr.keep_if {|s|s =~ /[z]/ }
=> []

irb(main):003:0> arr
=> []
irb(main):001:0> arr = %w[a b c d e]
=> ["a", "b", "c", "d", "e"]

irb(main):002:0> arr.keep_if {|s| s =~ /[a-z]/ }
=> ["a", "b", "c", "d", "e"]

irb(main):003:0> arr
=> ["a", "b", "c", "d", "e"]

# Array#select!は削除する要素がなかったときにnilを返す。ここが違うところ。
irb(main):004:0> brr = %w[a b c d e]
=> ["a", "b", "c", "d", "e"]

irb(main):005:0> brr.select! {|s| s =~ /[a-z]/ }
=> nil

irb(main):006:0> brr
=> ["a", "b", "c", "d", "e"]
# Array#select!はArray#keep_ifの処理に加えて他の処理もしている

[1] pry(main)> require 'pry-doc'
=> true

[2] pry(main)> show-source Array#keep_if

From: array.c (C Method):
Owner: Array
Visibility: public
Signature: keep_if()
Number of lines: 7

static VALUE
rb_ary_keep_if(VALUE ary)
{
    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
    rb_ary_select_bang(ary);
    return ary;
}

[3] pry(main)> show-source Array#select!

From: array.c (C Method):
Owner: Array
Visibility: public
Signature: select!()
Number of lines: 12

static VALUE
rb_ary_select_bang(VALUE ary)
{
    struct select_bang_arg args;

    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
    rb_ary_modify(ary);

    args.ary = ary;
    args.len[0] = args.len[1] = 0;
    return rb_ensure(select_bang_i, (VALUE)&args, select_bang_ensure, (VALUE)&args);
}
irb(main):001:0> arr = %w[a b c d e]
=> ["a", "b", "c", "d", "e"]

irb(main):002:0> enum = arr.keep_if
=> #<Enumerator: ["a", "b", "c", "d", "e"]:keep_if>

irb(main):003:0> arr[4] = 'z'
=> "z"

irb(main):004:0> enum
=> #<Enumerator: ["a", "b", "c", "d", "z"]:keep_if>

irb(main):005:0> enum.each {|s| s =~ /[acz]/ }
=> ["a", "c", "z"]

irb(main):006:0> enum
=> #<Enumerator: ["a", "c", "z"]:keep_if>