diff options
author | Jeremy Evans <code@jeremyevans.net> | 2019-06-17 11:33:44 -0700 |
---|---|---|
committer | Jeremy Evans <code@jeremyevans.net> | 2019-07-02 08:07:06 -0700 |
commit | ced640951b0e7164a12ea1770330eba3e6109fc2 (patch) | |
tree | 4a212c09d74e9fd611805f44c3af90e7d1119fd0 | |
parent | 649753b7f5410552c70931e32c193d83df3af97e (diff) | |
download | ruby-ced640951b0e7164a12ea1770330eba3e6109fc2.tar.gz |
Implement Array#minmax
Array#minmax was previous not implemented, so calling #minmax on
array was actually calling Enumerable#minmax. This is a simple
implementation of #minmax by just calling rb_ary_min and
rb_ary_max, which improves performance significantly.
Fixes [Bug #15929]
-rw-r--r-- | array.c | 21 | ||||
-rw-r--r-- | test/ruby/test_array.rb | 19 |
2 files changed, 40 insertions, 0 deletions
@@ -4850,6 +4850,26 @@ rb_ary_min(int argc, VALUE *argv, VALUE ary) return result; } +/* + * call-seq: + * ary.minmax -> [obj, obj] + * ary.minmax {| a,b | block } -> [obj, obj] + * + * Returns a two element array which contains the minimum and the + * maximum value in the array. + * + * Can be given an optional block to override the default comparison + * method <code>a <=> b</code>. + */ +static VALUE +rb_ary_minmax(VALUE ary) +{ + if (rb_block_given_p()) { + return rb_call_super(0, NULL); + } + return rb_assoc_new(rb_ary_min(0, 0, ary), rb_ary_max(0, 0, ary)); +} + static int push_value(st_data_t key, st_data_t val, st_data_t ary) { @@ -6902,6 +6922,7 @@ Init_Array(void) rb_define_method(rb_cArray, "max", rb_ary_max, -1); rb_define_method(rb_cArray, "min", rb_ary_min, -1); + rb_define_method(rb_cArray, "minmax", rb_ary_minmax, 0); rb_define_method(rb_cArray, "uniq", rb_ary_uniq, 0); rb_define_method(rb_cArray, "uniq!", rb_ary_uniq_bang, 0); diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index 6cb96ebe7a..c6aff553ff 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -1792,6 +1792,25 @@ class TestArray < Test::Unit::TestCase assert_same(obj, [obj, 1.0].max) end + def test_minmax + assert_equal([1, 3], [1, 2, 3, 1, 2].minmax) + assert_equal([3, 1], [1, 2, 3, 1, 2].minmax {|a,b| b <=> a }) + cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib } + assert_equal([[3, 2], [1, 3]], [1, 2, 3, 1, 2].each_with_index.minmax(&cond)) + ary = %w(albatross dog horse) + assert_equal(["albatross", "horse"], ary.minmax) + assert_equal(["dog", "albatross"], ary.minmax {|a,b| a.length <=> b.length }) + assert_equal([1, 3], [3,2,1].minmax) + + class << (obj = Object.new) + def <=>(x) 1 <=> x end + def coerce(x) [x, 1] end + end + ary = [obj, 1.0].minmax + assert_same(obj, ary[0]) + assert_equal(obj, ary[1]) + end + def test_uniq a = [] b = a.uniq |