summaryrefslogtreecommitdiff
path: root/enum.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2019-02-07 08:14:10 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2019-02-07 08:14:10 +0000
commit673dc51c251588be3c9f4b5b5486cd80d46dfeee (patch)
tree9e26efcb7b1858e6fb477f28b229b8326301adad /enum.c
parente0f1b514d2f78fe5ea17ddf240307cafbf47fccf (diff)
enum.c: Enumerable#tally
* enum.c (enum_tally): new methods Enumerable#tally, which group and count elements of the collection. [Feature #11076] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67020 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'enum.c')
-rw-r--r--enum.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/enum.c b/enum.c
index 5ba4092..3c6b7ee 100644
--- a/enum.c
+++ b/enum.c
@@ -935,6 +935,48 @@ enum_group_by(VALUE obj)
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)
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);