* array.c (rb_ary_max, rb_ary_min): Array#max and Array#min added.
[Feature #12172] * internal.h (OPTIMIZED_CMP): moved from enum.c so that array.c can use it. * test/ruby/test_array.rb (test_max, test_min): tests for Array#max and Array#min. * test/ruby/test_enum.rb (test_max, test_min): revised a bit to test Enumerable#max and #min explicitly. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54150 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
a22455199b
commit
68a6f2e9e0
16
ChangeLog
16
ChangeLog
@ -1,4 +1,18 @@
|
||||
Thu Mar 17 21:02:42 2016 Yusuke Endoh <mame@tsg.ne.jp>
|
||||
Thu Mar 17 21:09:34 2016 Yusuke Endoh <mame@ruby-lang.org>
|
||||
|
||||
* array.c (rb_ary_max, rb_ary_min): Array#max and Array#min added.
|
||||
[Feature #12172]
|
||||
|
||||
* internal.h (OPTIMIZED_CMP): moved from enum.c so that array.c can
|
||||
use it.
|
||||
|
||||
* test/ruby/test_array.rb (test_max, test_min): tests for Array#max
|
||||
and Array#min.
|
||||
|
||||
* test/ruby/test_enum.rb (test_max, test_min): revised a bit to test
|
||||
Enumerable#max and #min explicitly.
|
||||
|
||||
Thu Mar 17 21:02:42 2016 Yusuke Endoh <mame@ruby-lang.org>
|
||||
|
||||
* internal.c: struct cmp_opt_data added for refactoring out a data
|
||||
structure for CMP_OPTIMIZABLE
|
||||
|
93
array.c
93
array.c
@ -4178,6 +4178,96 @@ rb_ary_or(VALUE ary1, VALUE ary2)
|
||||
return ary3;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* ary.max -> obj
|
||||
* ary.max { |a, b| block } -> obj
|
||||
* ary.max(n) -> array
|
||||
* ary.max(n) {|a,b| block } -> array
|
||||
*
|
||||
* Returns the object in _ary_ 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"
|
||||
*
|
||||
* If the +n+ argument is given, maximum +n+ elements are returned
|
||||
* as an array.
|
||||
*
|
||||
* a = %w[albatross dog horse]
|
||||
* a.max(2) #=> ["horse", "dog"]
|
||||
* a.max(2) {|a, b| a.length <=> b.length } #=> ["albatross", "horse"]
|
||||
*/
|
||||
static VALUE
|
||||
rb_ary_max(int argc, VALUE *argv, VALUE ary)
|
||||
{
|
||||
struct cmp_opt_data cmp_opt = { 0, 0 };
|
||||
VALUE result = Qundef, v;
|
||||
VALUE num;
|
||||
long i;
|
||||
|
||||
rb_scan_args(argc, argv, "01", &num);
|
||||
|
||||
if (!NIL_P(num) || rb_block_given_p())
|
||||
return rb_call_super(argc, argv); /* XXX: should redefine? */
|
||||
|
||||
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
||||
v = RARRAY_AREF(ary, i);
|
||||
if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) > 0) {
|
||||
result = v;
|
||||
}
|
||||
}
|
||||
if (result == Qundef) return Qnil;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* ary.min -> obj
|
||||
* ary.min {| a,b | block } -> obj
|
||||
* ary.min(n) -> array
|
||||
* ary.min(n) {| a,b | block } -> array
|
||||
*
|
||||
* Returns the object in _ary_ with the minimum 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.min #=> "albatross"
|
||||
* a.min { |a, b| a.length <=> b.length } #=> "dog"
|
||||
*
|
||||
* If the +n+ argument is given, minimum +n+ elements are returned
|
||||
* as an array.
|
||||
*
|
||||
* a = %w[albatross dog horse]
|
||||
* a.min(2) #=> ["albatross", "dog"]
|
||||
* a.min(2) {|a, b| a.length <=> b.length } #=> ["dog", "horse"]
|
||||
*/
|
||||
static VALUE
|
||||
rb_ary_min(int argc, VALUE *argv, VALUE ary)
|
||||
{
|
||||
struct cmp_opt_data cmp_opt = { 0, 0 };
|
||||
VALUE result = Qundef, v;
|
||||
VALUE num;
|
||||
long i;
|
||||
|
||||
rb_scan_args(argc, argv, "01", &num);
|
||||
|
||||
if (!NIL_P(num) || rb_block_given_p())
|
||||
return rb_call_super(argc, argv); /* XXX: should redefine? */
|
||||
|
||||
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
||||
v = RARRAY_AREF(ary, i);
|
||||
if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) < 0) {
|
||||
result = v;
|
||||
}
|
||||
}
|
||||
if (result == Qundef) return Qnil;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
push_value(st_data_t key, st_data_t val, st_data_t ary)
|
||||
{
|
||||
@ -5867,6 +5957,9 @@ Init_Array(void)
|
||||
rb_define_method(rb_cArray, "&", rb_ary_and, 1);
|
||||
rb_define_method(rb_cArray, "|", rb_ary_or, 1);
|
||||
|
||||
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, "uniq", rb_ary_uniq, 0);
|
||||
rb_define_method(rb_cArray, "uniq!", rb_ary_uniq_bang, 0);
|
||||
rb_define_method(rb_cArray, "compact", rb_ary_compact, 0);
|
||||
|
7
enum.c
7
enum.c
@ -1486,13 +1486,6 @@ enum_none(VALUE obj)
|
||||
return memo->v1;
|
||||
}
|
||||
|
||||
#define OPTIMIZED_CMP(a, b, data) \
|
||||
((FIXNUM_P(a) && FIXNUM_P(b) && CMP_OPTIMIZABLE(data, Fixnum)) ? \
|
||||
(((long)a > (long)b) ? 1 : ((long)a < (long)b) ? -1 : 0) : \
|
||||
(STRING_P(a) && STRING_P(b) && CMP_OPTIMIZABLE(data, String)) ? \
|
||||
rb_str_cmp(a, b) : \
|
||||
rb_cmpint(rb_funcallv(a, id_cmp, 1, &b), a, b))
|
||||
|
||||
struct min_t {
|
||||
VALUE min;
|
||||
struct cmp_opt_data cmp_opt;
|
||||
|
@ -698,6 +698,13 @@ struct cmp_opt_data {
|
||||
rb_method_basic_definition_p(TOKEN_PASTE(rb_c,type), id_cmp) && \
|
||||
((data).opt_methods |= CMP_OPTIMIZABLE_BIT(type))))
|
||||
|
||||
#define OPTIMIZED_CMP(a, b, data) \
|
||||
((FIXNUM_P(a) && FIXNUM_P(b) && CMP_OPTIMIZABLE(data, Fixnum)) ? \
|
||||
(((long)a > (long)b) ? 1 : ((long)a < (long)b) ? -1 : 0) : \
|
||||
(STRING_P(a) && STRING_P(b) && CMP_OPTIMIZABLE(data, String)) ? \
|
||||
rb_str_cmp(a, b) : \
|
||||
rb_cmpint(rb_funcallv(a, id_cmp, 1, &b), a, b))
|
||||
|
||||
/* ment is in method.h */
|
||||
|
||||
/* global variable */
|
||||
|
@ -1552,6 +1552,37 @@ class TestArray < Test::Unit::TestCase
|
||||
assert_equal "wrong array length at 2 (expected 2, was 1)", e.message
|
||||
end
|
||||
|
||||
def test_min
|
||||
assert_equal(1, [1, 2, 3, 1, 2].min)
|
||||
assert_equal(3, [1, 2, 3, 1, 2].min {|a,b| b <=> a })
|
||||
cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib }
|
||||
assert_equal([3, 2], [1, 2, 3, 1, 2].each_with_index.min(&cond))
|
||||
ary = %w(albatross dog horse)
|
||||
assert_equal("albatross", ary.min)
|
||||
assert_equal("dog", ary.min {|a,b| a.length <=> b.length })
|
||||
assert_equal(1, [3,2,1].min)
|
||||
assert_equal(%w[albatross dog], ary.min(2))
|
||||
assert_equal(%w[dog horse],
|
||||
ary.min(2) {|a,b| a.length <=> b.length })
|
||||
assert_equal([13, 14], [20, 32, 32, 21, 30, 25, 29, 13, 14].min(2))
|
||||
assert_equal([2, 4, 6, 7], [2, 4, 8, 6, 7].min(4))
|
||||
end
|
||||
|
||||
def test_max
|
||||
assert_equal(3, [1, 2, 3, 1, 2].max)
|
||||
assert_equal(1, [1, 2, 3, 1, 2].max {|a,b| b <=> a })
|
||||
cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib }
|
||||
assert_equal([1, 3], [1, 2, 3, 1, 2].each_with_index.max(&cond))
|
||||
ary = %w(albatross dog horse)
|
||||
assert_equal("horse", ary.max)
|
||||
assert_equal("albatross", ary.max {|a,b| a.length <=> b.length })
|
||||
assert_equal(1, [3,2,1].max{|a,b| b <=> a })
|
||||
assert_equal(%w[horse dog], ary.max(2))
|
||||
assert_equal(%w[albatross horse],
|
||||
ary.max(2) {|a,b| a.length <=> b.length })
|
||||
assert_equal([3, 2], [0, 0, 0, 0, 0, 0, 1, 3, 2].max(2))
|
||||
end
|
||||
|
||||
def test_uniq
|
||||
a = []
|
||||
b = a.uniq
|
||||
|
@ -331,15 +331,15 @@ class TestEnumerable < Test::Unit::TestCase
|
||||
assert_equal(3, @obj.min {|a,b| b <=> a })
|
||||
cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib }
|
||||
assert_equal([3, 2], @obj.each_with_index.min(&cond))
|
||||
ary = %w(albatross dog horse)
|
||||
assert_equal("albatross", ary.min)
|
||||
assert_equal("dog", ary.min {|a,b| a.length <=> b.length })
|
||||
assert_equal(1, [3,2,1].min)
|
||||
assert_equal(%w[albatross dog], ary.min(2))
|
||||
enum = %w(albatross dog horse).to_enum
|
||||
assert_equal("albatross", enum.min)
|
||||
assert_equal("dog", enum.min {|a,b| a.length <=> b.length })
|
||||
assert_equal(1, [3,2,1].to_enum.min)
|
||||
assert_equal(%w[albatross dog], enum.min(2))
|
||||
assert_equal(%w[dog horse],
|
||||
ary.min(2) {|a,b| a.length <=> b.length })
|
||||
assert_equal([13, 14], [20, 32, 32, 21, 30, 25, 29, 13, 14].min(2))
|
||||
assert_equal([2, 4, 6, 7], [2, 4, 8, 6, 7].min(4))
|
||||
enum.min(2) {|a,b| a.length <=> b.length })
|
||||
assert_equal([13, 14], [20, 32, 32, 21, 30, 25, 29, 13, 14].to_enum.min(2))
|
||||
assert_equal([2, 4, 6, 7], [2, 4, 8, 6, 7].to_enum.min(4))
|
||||
end
|
||||
|
||||
def test_max
|
||||
@ -347,14 +347,14 @@ class TestEnumerable < Test::Unit::TestCase
|
||||
assert_equal(1, @obj.max {|a,b| b <=> a })
|
||||
cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib }
|
||||
assert_equal([1, 3], @obj.each_with_index.max(&cond))
|
||||
ary = %w(albatross dog horse)
|
||||
assert_equal("horse", ary.max)
|
||||
assert_equal("albatross", ary.max {|a,b| a.length <=> b.length })
|
||||
assert_equal(1, [3,2,1].max{|a,b| b <=> a })
|
||||
assert_equal(%w[horse dog], ary.max(2))
|
||||
enum = %w(albatross dog horse).to_enum
|
||||
assert_equal("horse", enum.max)
|
||||
assert_equal("albatross", enum.max {|a,b| a.length <=> b.length })
|
||||
assert_equal(1, [3,2,1].to_enum.max{|a,b| b <=> a })
|
||||
assert_equal(%w[horse dog], enum.max(2))
|
||||
assert_equal(%w[albatross horse],
|
||||
ary.max(2) {|a,b| a.length <=> b.length })
|
||||
assert_equal([3, 2], [0, 0, 0, 0, 0, 0, 1, 3, 2].max(2))
|
||||
enum.max(2) {|a,b| a.length <=> b.length })
|
||||
assert_equal([3, 2], [0, 0, 0, 0, 0, 0, 1, 3, 2].to_enum.max(2))
|
||||
end
|
||||
|
||||
def test_minmax
|
||||
|
Loading…
x
Reference in New Issue
Block a user