summaryrefslogtreecommitdiff
path: root/enum.c
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-07-14 14:51:42 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-07-14 14:51:42 +0000
commit6c6a24826c5fda68e04e71ac17620b0e70bca265 (patch)
treec2692457fbae375c8a38fd64a90a852365e331fc /enum.c
parent1a760a6f76e5b2fad343fce10ebf831fe22286b4 (diff)
* enum.c (enum_min_by): new method Enum#min_by. added Enum#max_by
as well. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@6629 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'enum.c')
-rw-r--r--enum.c102
1 files changed, 88 insertions, 14 deletions
diff --git a/enum.c b/enum.c
index 08a1fde747..212e0f3b54 100644
--- a/enum.c
+++ b/enum.c
@@ -677,20 +677,6 @@ enum_min(obj)
return result;
}
-/*
- * call-seq:
- * enum.max => obj
- * enum.max {| a,b | block } => obj
- *
- * Returns the object in <i>enum</i> with the maximum value. The
- * first form assumes all objects implement <code>Comparable</code>;
- * the second uses the block to return <em>a <=> b</em>.
- *
- * a = %w(albatross dog horse)
- * a.max #=> "horse"
- * a.max {|a,b| a.length <=> b.length } #=> "albatross"
- */
-
static VALUE
max_i(i, memo)
VALUE i;
@@ -757,6 +743,92 @@ enum_max(obj)
}
static VALUE
+min_by_i(i, memo)
+ VALUE i;
+ NODE *memo;
+{
+ VALUE v;
+
+ v = rb_yield(i);
+ if (NIL_P(memo->u1.value)) {
+ memo->u1.value = v;
+ memo->u2.value = i;
+ }
+ else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo->u1.value), v, memo->u1.value) < 0) {
+ memo->u1.value = v;
+ memo->u2.value = i;
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.min_by {| obj| block } => obj
+ *
+ * Returns the object in <i>enum</i> that gives the minimum
+ * value from the given block.
+ *
+ * a = %w(albatross dog horse)
+ * a.min_by {|x| x.length } #=> "dog"
+ */
+
+static VALUE
+enum_min_by(obj)
+ VALUE obj;
+{
+ VALUE result;
+ NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
+
+ rb_iterate(rb_each, obj, min_by_i, (VALUE)memo);
+ result = memo->u2.value;
+ rb_gc_force_recycle((VALUE)memo);
+ return result;
+}
+
+static VALUE
+max_by_i(i, memo)
+ VALUE i;
+ NODE *memo;
+{
+ VALUE v;
+
+ v = rb_yield(i);
+ if (NIL_P(memo->u1.value)) {
+ memo->u1.value = v;
+ memo->u2.value = i;
+ }
+ else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo->u1.value), v, memo->u1.value) > 0) {
+ memo->u1.value = v;
+ memo->u2.value = i;
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.max_by {| obj| block } => obj
+ *
+ * Returns the object in <i>enum</i> that gives the maximum
+ * value from the given block.
+ *
+ * a = %w(albatross dog horse)
+ * a.max_by {|x| x.length } #=> "albatross"
+ */
+
+static VALUE
+enum_max_by(obj)
+ VALUE obj;
+{
+ VALUE result;
+ NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
+
+ rb_iterate(rb_each, obj, max_by_i, (VALUE)memo);
+ result = memo->u2.value;
+ rb_gc_force_recycle((VALUE)memo);
+ return result;
+}
+
+static VALUE
member_i(item, memo)
VALUE item;
NODE *memo;
@@ -933,6 +1005,8 @@ Init_Enumerable()
rb_define_method(rb_mEnumerable,"any?", enum_any, 0);
rb_define_method(rb_mEnumerable,"min", enum_min, 0);
rb_define_method(rb_mEnumerable,"max", enum_max, 0);
+ rb_define_method(rb_mEnumerable,"min_by", enum_min_by, 0);
+ rb_define_method(rb_mEnumerable,"max_by", enum_max_by, 0);
rb_define_method(rb_mEnumerable,"member?", enum_member, 1);
rb_define_method(rb_mEnumerable,"include?", enum_member, 1);
rb_define_method(rb_mEnumerable,"each_with_index", enum_each_with_index, 0);