summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorknu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-04-10 11:12:08 +0000
committerknu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-04-10 11:12:08 +0000
commiteeae41fba9ce19d9c0ce7cc1e9f66ae6bcb39f73 (patch)
treeb73f0f39b744fd18c0895ee3aad525b04e489eb8
parent626dc4a46097f0c4484faa1a0b8a3f48b911fca3 (diff)
* enum.c (enum_first, enum_group_by): New methods:
Enumerable#first and #group_by; backported from 1.9. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@15956 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog5
-rw-r--r--NEWS5
-rw-r--r--enum.c102
3 files changed, 112 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 5a1cee9d81..ba72311f54 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Thu Apr 10 20:08:37 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enum.c (enum_first, enum_group_by): New methods:
+ Enumerable#first and #group_by; backported from 1.9.
+
Thu Apr 10 19:49:10 2008 Akinori MUSHA <knu@iDaemons.org>
* enumerator.c (rb_eStopIteration), eval.c (rb_f_loop), ruby.h:
diff --git a/NEWS b/NEWS
index 763df539d5..7f70f105aa 100644
--- a/NEWS
+++ b/NEWS
@@ -54,6 +54,11 @@ with all sufficient information, see the ChangeLog file.
New methods for various enumeration defined by the enumerator library.
+ * Enumerable#first
+ * Enumerable#group_by
+
+ New methods.
+
* Integer#ord implemented.
* Integer#odd? implemented.
* Integer#even? implemented.
diff --git a/enum.c b/enum.c
index 5e23bcff7e..a22cb4c639 100644
--- a/enum.c
+++ b/enum.c
@@ -386,6 +386,106 @@ enum_partition(obj)
return rb_assoc_new(ary[0], ary[1]);
}
+static VALUE
+group_by_i(i, hash)
+ VALUE i;
+ VALUE hash;
+{
+ VALUE group = rb_yield(i);
+ VALUE values;
+
+ values = rb_hash_aref(hash, group);
+ if (NIL_P(values)) {
+ values = rb_ary_new3(1, i);
+ rb_hash_aset(hash, group, values);
+ }
+ else {
+ rb_ary_push(values, i);
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.group_by {| obj | block } => a_hash
+ *
+ * Returns a hash, which keys are evaluated result from the
+ * block, and values are arrays of elements in <i>enum</i>
+ * corresponding to the key.
+ *
+ * (1..6).group_by {|i| i%3} #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
+ *
+ */
+
+static VALUE
+enum_group_by(obj)
+ VALUE obj;
+{
+ VALUE hash;
+
+ RETURN_ENUMERATOR(obj, 0, 0);
+
+ hash = rb_hash_new();
+ rb_block_call(obj, id_each, 0, 0, group_by_i, hash);
+
+ return hash;
+}
+
+static VALUE
+first_i(i, ary)
+ VALUE i;
+ VALUE *ary;
+{
+ if (NIL_P(ary[0])) {
+ ary[1] = i;
+ rb_iter_break();
+ }
+ else {
+ long n = NUM2LONG(ary[0]);
+
+ if (n <= 0) {
+ rb_iter_break();
+ }
+ rb_ary_push(ary[1], i);
+ n--;
+ ary[0] = INT2NUM(n);
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.first -> obj or nil
+ * enum.first(n) -> an_array
+ *
+ * Returns the first element, or the first +n+ elements, of the enumerable.
+ * If the enumerable is empty, the first form returns <code>nil</code>, and the
+ * second form returns an empty array.
+ *
+ */
+
+static VALUE
+enum_first(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ VALUE n, ary[2];
+
+ if (argc == 0) {
+ ary[0] = ary[1] = Qnil;
+ }
+ else {
+ rb_scan_args(argc, argv, "01", &n);
+ ary[0] = n;
+ ary[1] = rb_ary_new2(NUM2LONG(n));
+ }
+ rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)ary);
+
+ return ary[1];
+}
+
+
/*
* call-seq:
* enum.sort => array
@@ -959,6 +1059,8 @@ Init_Enumerable()
rb_define_method(rb_mEnumerable,"map", enum_collect, 0);
rb_define_method(rb_mEnumerable,"inject", 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,"first", enum_first, -1);
rb_define_method(rb_mEnumerable,"all?", enum_all, 0);
rb_define_method(rb_mEnumerable,"any?", enum_any, 0);
rb_define_method(rb_mEnumerable,"min", enum_min, 0);