[前][次][番号順一覧][スレッド一覧]

ruby-changes:42503

From: akr <ko1@a...>
Date: Thu, 14 Apr 2016 20:52:07 +0900 (JST)
Subject: [ruby-changes:42503] akr:r54577 (trunk): * array.c (rb_ary_sum): Support the optional argument, init, and block.

akr	2016-04-14 21:48:44 +0900 (Thu, 14 Apr 2016)

  New Revision: 54577

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=54577

  Log:
    * array.c (rb_ary_sum): Support the optional argument, init, and block.

  Modified files:
    trunk/ChangeLog
    trunk/array.c
    trunk/test/ruby/test_array.rb
Index: array.c
===================================================================
--- array.c	(revision 54576)
+++ array.c	(revision 54577)
@@ -5652,37 +5652,49 @@ rb_ary_dig(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/array.c#L5652
 
 /*
  * call-seq:
- *   ary.sum                 -> number
+ *   ary.sum(init=0)                    -> number
+ *   ary.sum(init=0) {|e| expr }        -> number
  *
  * Returns the sum of elements.
- * For example, [e1, e2, e3].sum returns 0 + e1 + e2 + e3.
+ * For example, [e1, e2, e3].sum returns init + e1 + e2 + e3.
  *
- * If <i>ary</i> is empty, it returns 0.
+ * If a block is given, the block is applied to each element
+ * before addtion.
  *
- *   [].sum                     #=> 0
- *   [1, 2, 3].sum              #=> 6
- *   [3, 5.5].sum               #=> 8.5
- *   [Object.new].sum           #=> TypeError
+ * If <i>ary</i> is empty, it returns <i>init</i>.
+ *
+ *   [].sum                             #=> 0
+ *   [].sum(0.0)                        #=> 0.0
+ *   [1, 2, 3].sum                      #=> 6
+ *   [3, 5.5].sum                       #=> 8.5
+ *   [2.5, 3.0].sum(0.0) {|v| v * v }   #=> 15.25
+ *   [Object.new].sum                   #=> TypeError
  *
  * This method may not respect method redefinition of "+" methods
  * such as Fixnum#+.
  *
  */
 
-VALUE
-rb_ary_sum(VALUE ary)
+static VALUE
+rb_ary_sum(int argc, VALUE *argv, VALUE ary)
 {
-    VALUE v, e;
+    VALUE e, v;
     long i, n;
+    int block_given;
 
-    if (RARRAY_LEN(ary) == 0)
-        return LONG2FIX(0);
+    if (rb_scan_args(argc, argv, "01", &v) == 0)
+        v = LONG2FIX(0);
 
-    v = LONG2FIX(0);
+    block_given = rb_block_given_p();
+
+    if (RARRAY_LEN(ary) == 0)
+        return v;
 
     n = 0;
     for (i = 0; i < RARRAY_LEN(ary); i++) {
         e = RARRAY_AREF(ary, i);
+        if (block_given)
+            e = rb_yield(e);
         if (FIXNUM_P(e)) {
             n += FIX2LONG(e); /* should not overflow long type */
             if (!FIXABLE(n)) {
@@ -5711,6 +5723,8 @@ rb_ary_sum(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L5723
         for (; i < RARRAY_LEN(ary); i++) {
             double x, y, t;
             e = RARRAY_AREF(ary, i);
+            if (block_given)
+                e = rb_yield(e);
             if (RB_FLOAT_TYPE_P(e))
                 x = RFLOAT_VALUE(e);
             else if (FIXNUM_P(e))
@@ -5732,7 +5746,10 @@ rb_ary_sum(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L5746
     }
 
     for (; i < RARRAY_LEN(ary); i++) {
-        v = rb_funcall(v, idPLUS, 1, RARRAY_AREF(ary, i));
+        e = RARRAY_AREF(ary, i);
+        if (block_given)
+            e = rb_yield(e);
+        v = rb_funcall(v, idPLUS, 1, e);
     }
     return v;
 }
@@ -6092,7 +6109,7 @@ Init_Array(void) https://github.com/ruby/ruby/blob/trunk/array.c#L6109
     rb_define_method(rb_cArray, "bsearch_index", rb_ary_bsearch_index, 0);
     rb_define_method(rb_cArray, "any?", rb_ary_any_p, 0);
     rb_define_method(rb_cArray, "dig", rb_ary_dig, -1);
-    rb_define_method(rb_cArray, "sum", rb_ary_sum, 0);
+    rb_define_method(rb_cArray, "sum", rb_ary_sum, -1);
 
     id_cmp = rb_intern("<=>");
     id_random = rb_intern("random");
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 54576)
+++ ChangeLog	(revision 54577)
@@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Thu Apr 14 21:46:36 2016  Tanaka Akira  <akr@f...>
+
+	* array.c (rb_ary_sum): Support the optional argument, init, and
+	  block.
+
 Thu Apr 14 19:02:41 2016  NARUSE, Yui  <naruse@r...>
 
 	* lib/irb/ext/save-history.rb: suppress warning: method redefined;
Index: test/ruby/test_array.rb
===================================================================
--- test/ruby/test_array.rb	(revision 54576)
+++ test/ruby/test_array.rb	(revision 54577)
@@ -2714,34 +2714,42 @@ class TestArray < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_array.rb#L2714
   FIXNUM_MIN = -(1 << (8 * RbConfig::SIZEOF['long'] - 2))
   FIXNUM_MAX = (1 << (8 * RbConfig::SIZEOF['long'] - 2)) - 1
 
+  def assert_int_equal(e, v, msg=nil)
+    assert_kind_of(Integer, v, msg)
+    assert_equal(e, v, msg)
+  end
+
   def assert_float_equal(e, v, msg=nil)
     assert_equal(Float, v.class, msg)
     assert_equal(e, v, msg)
   end
 
   def test_sum
-    assert_equal(0, [].sum)
-    assert_equal(3, [3].sum)
-    assert_equal(8, [3, 5].sum)
-    assert_equal(15, [3, 5, 7].sum)
+    assert_int_equal(0, [].sum)
+    assert_float_equal(0.0, [].sum(0.0))
+    assert_int_equal(3, [3].sum)
+    assert_int_equal(8, [3, 5].sum)
+    assert_int_equal(15, [3, 5, 7].sum)
     assert_float_equal(15.0, [3, 5, 7.0].sum)
-    assert_equal(2*FIXNUM_MAX, Array.new(2, FIXNUM_MAX).sum)
-    assert_equal(2*(FIXNUM_MAX+1), Array.new(2, FIXNUM_MAX+1).sum)
-    assert_equal(10*FIXNUM_MAX, Array.new(10, FIXNUM_MAX).sum)
-    assert_equal(0, ([FIXNUM_MAX, 1, -FIXNUM_MAX, -1]*10).sum)
-    assert_equal(FIXNUM_MAX*10, ([FIXNUM_MAX+1, -1]*10).sum)
-    assert_equal(2*FIXNUM_MIN, Array.new(2, FIXNUM_MIN).sum)
-    assert_equal((FIXNUM_MAX+1).to_f, [FIXNUM_MAX, 1, 0.0].sum)
+    assert_int_equal(2*FIXNUM_MAX, Array.new(2, FIXNUM_MAX).sum)
+    assert_int_equal(2*(FIXNUM_MAX+1), Array.new(2, FIXNUM_MAX+1).sum)
+    assert_int_equal(10*FIXNUM_MAX, Array.new(10, FIXNUM_MAX).sum)
+    assert_int_equal(0, ([FIXNUM_MAX, 1, -FIXNUM_MAX, -1]*10).sum)
+    assert_int_equal(FIXNUM_MAX*10, ([FIXNUM_MAX+1, -1]*10).sum)
+    assert_int_equal(2*FIXNUM_MIN, Array.new(2, FIXNUM_MIN).sum)
+    assert_float_equal((FIXNUM_MAX+1).to_f, [FIXNUM_MAX, 1, 0.0].sum)
     assert_float_equal(8.0, [3.0, 5].sum)
     assert_float_equal((FIXNUM_MAX+1).to_f, [0.0, FIXNUM_MAX+1].sum)
     assert_equal(2.0+3.0i, [2.0, 3.0i].sum)
+    assert_int_equal(13, [1, 2].sum(10))
+    assert_int_equal(16, [1, 2].sum(10) {|v| v * 2 })
 
     large_number = 100000000
     small_number = 1e-9
     until (large_number + small_number) == large_number
       small_number /= 10
     end
-    assert_equal(large_number+(small_number*10), [large_number, *[small_number]*10].sum)
+    assert_float_equal(large_number+(small_number*10), [large_number, *[small_number]*10].sum)
   end
 
   private

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]