diff options
author | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-03-03 05:35:08 +0000 |
---|---|---|
committer | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-03-03 05:35:08 +0000 |
commit | 006a8ba77f6c5e27201760dfe560eb0c63e4d70b (patch) | |
tree | 63fd911e1975280a0f959743ac55c646cc383a88 | |
parent | 35345f1c09b6e08e674fb7cbad3258cd1acdd91d (diff) | |
download | ruby-006a8ba77f6c5e27201760dfe560eb0c63e4d70b.tar.gz |
* array.c (rb_ary_select_bang): select! removes all elements for
which block returns false. [ruby-core:27286]
* array.c (rb_ary_keep_if): #keep_if, new method.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@26800 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | array.c | 53 | ||||
-rw-r--r-- | test/ruby/test_array.rb | 16 |
3 files changed, 76 insertions, 0 deletions
@@ -1,3 +1,10 @@ +Wed Mar 3 14:28:23 2010 Yukihiro Matsumoto <matz@ruby-lang.org> + + * array.c (rb_ary_select_bang): select! removes all elements for + which block returns false. [ruby-core:27286] + + * array.c (rb_ary_keep_if): #keep_if, new method. + Wed Mar 3 06:19:25 2010 Nobuyoshi Nakada <nobu@ruby-lang.org> * win32/win32.c (signbig): defined. @@ -2250,6 +2250,57 @@ rb_ary_select(VALUE ary) /* * call-seq: + * array.select! {|item| block } -> an_array + * + * Invokes the block passing in successive elements from + * <i>array</i>, deleting elements for which the block returns a + * false value. but returns <code>nil</code> if no changes were + * made. Also see <code>Array#keep_if</code> + */ + +static VALUE +rb_ary_select_bang(VALUE ary) +{ + long i1, i2; + + RETURN_ENUMERATOR(ary, 0, 0); + rb_ary_modify(ary); + for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) { + VALUE v = RARRAY_PTR(ary)[i1]; + if (!RTEST(rb_yield(v))) continue; + if (i1 != i2) { + rb_ary_store(ary, i2, v); + } + i2++; + } + + if (RARRAY_LEN(ary) == i2) return Qnil; + if (i2 < RARRAY_LEN(ary)) + ARY_SET_LEN(ary, i2); + return ary; +} + +/* + * call-seq: + * array.keep_if {|item| block } -> an_array + * + * Deletes every element of <i>self</i> for which <i>block</i> evaluates + * to <code>false</code>. + * + * a = %w{ a b c d e f } + * a.keep_if {|v| v =~ /[aeiou]/} #=> ["a", "e"] + */ + +static VALUE +rb_ary_keep_if(VALUE ary) +{ + RETURN_ENUMERATOR(ary, 0, 0); + rb_ary_select_bang(ary); + return ary; +} + +/* + * call-seq: * array.delete(obj) -> obj or nil * array.delete(obj) { block } -> obj or nil * @@ -4239,6 +4290,8 @@ Init_Array(void) rb_define_method(rb_cArray, "map", rb_ary_collect, 0); rb_define_method(rb_cArray, "map!", rb_ary_collect_bang, 0); rb_define_method(rb_cArray, "select", rb_ary_select, 0); + rb_define_method(rb_cArray, "select!", rb_ary_select_bang, 0); + rb_define_method(rb_cArray, "keep_if", rb_ary_keep_if, 0); rb_define_method(rb_cArray, "values_at", rb_ary_values_at, -1); rb_define_method(rb_cArray, "delete", rb_ary_delete, 1); rb_define_method(rb_cArray, "delete_at", rb_ary_delete_at_m, 1); diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index a0dbef0cb8..7101d33012 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -1590,6 +1590,22 @@ class TestArray < Test::Unit::TestCase assert_equal([0, 2], [0, 1, 2, 3].select {|x| x % 2 == 0 }) end + # also keep_if + def test_select! + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(nil, a.select! { true }) + assert_equal(a, a.keep_if { true }) + assert_equal(@cls[1, 2, 3, 4, 5], a) + + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(a, a.select! { false }) + assert_equal(@cls[], a) + + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(a, a.select! { |i| i > 3 }) + assert_equal(@cls[4, 5], a) + end + def test_delete2 a = [0] * 1024 + [1] + [0] * 1024 a.delete(0) |