ruby-changes:54800
From: nobu <ko1@a...>
Date: Thu, 7 Feb 2019 17:14:15 +0900 (JST)
Subject: [ruby-changes:54800] nobu:r67020 (trunk): enum.c: Enumerable#tally
nobu 2019-02-07 17:14:10 +0900 (Thu, 07 Feb 2019) New Revision: 67020 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=67020 Log: enum.c: Enumerable#tally * enum.c (enum_tally): new methods Enumerable#tally, which group and count elements of the collection. [Feature #11076] Modified files: trunk/NEWS trunk/enum.c trunk/test/ruby/test_enum.rb Index: enum.c =================================================================== --- enum.c (revision 67019) +++ enum.c (revision 67020) @@ -935,6 +935,48 @@ enum_group_by(VALUE obj) https://github.com/ruby/ruby/blob/trunk/enum.c#L935 return enum_hashify(obj, 0, 0, group_by_i); } +static void +tally_up(VALUE hash, VALUE group) +{ + VALUE tally = rb_hash_aref(hash, group); + if (NIL_P(tally)) { + tally = INT2FIX(1); + } + else if (FIXNUM_P(tally) && tally < INT2FIX(FIXNUM_MAX)) { + tally += INT2FIX(1) & ~FIXNUM_FLAG; + } + else { + tally = rb_big_plus(tally, INT2FIX(1)); + } + rb_hash_aset(hash, group, tally); +} + +static VALUE +tally_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash)) +{ + ENUM_WANT_SVALUE(); + tally_up(hash, i); + return Qnil; +} + +/* + * call-seq: + * enum.tally -> a_hash + * + * Tallys the collection. Returns a hash where the keys are the + * elements and the values are numbers of elements in the collection + * that correspond to the key. + * + * (1..6).tally { |i| i%3 } #=> {0=>2, 1=>2, 2=>2} + * + */ + +static VALUE +enum_tally(VALUE obj) +{ + return enum_hashify(obj, 0, 0, tally_i); +} + static VALUE first_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, params)) { @@ -4070,6 +4112,7 @@ Init_Enumerable(void) https://github.com/ruby/ruby/blob/trunk/enum.c#L4112 rb_define_method(rb_mEnumerable, "reduce", enum_inject, -1); rb_define_method(rb_mEnumerable, "partition", enum_partition, 0); rb_define_method(rb_mEnumerable, "group_by", enum_group_by, 0); + rb_define_method(rb_mEnumerable, "tally", enum_tally, 0); rb_define_method(rb_mEnumerable, "first", enum_first, -1); rb_define_method(rb_mEnumerable, "all?", enum_all, -1); rb_define_method(rb_mEnumerable, "any?", enum_any, -1); Index: NEWS =================================================================== --- NEWS (revision 67019) +++ NEWS (revision 67020) @@ -24,6 +24,12 @@ sufficient information, see the ChangeLo https://github.com/ruby/ruby/blob/trunk/NEWS#L24 === Core classes updates (outstanding ones only) +Enumerable:: + + New method:: + + * Added Enumerable#tally. [Feature #11076] + === Stdlib updates (outstanding ones only) CSV:: Index: test/ruby/test_enum.rb =================================================================== --- test/ruby/test_enum.rb (revision 67019) +++ test/ruby/test_enum.rb (revision 67020) @@ -294,6 +294,11 @@ class TestEnumerable < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enum.rb#L294 assert_equal(h, @obj.each_with_index.group_by(&cond)) end + def test_tally + h = {1 => 2, 2 => 2, 3 => 1} + assert_equal(h, @obj.tally) + end + def test_first assert_equal(1, @obj.first) assert_equal([1, 2, 3], @obj.first(3)) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/