From fd04b75d6b8f329c1e383015a507766ceb495980 Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Sat, 23 Mar 2019 18:55:13 +0900 Subject: [PATCH] Add Array#reverse_sort/reverse_sort_by methods This patch introduces these methods to Array: * `reverse_sort` * `reverse_sort!` * `reverse_sort_by` * `reverse_sort_by!` These methods are accessory methods build on top of `sort`, `sort!`, `sort_by`, and `sort_by!` method. They are as-if user calls those methods and call `reverse!` on it. These methods are proposed as this will encourage users to use the fastest way to perform a reverse sort on an Array, as one may not know that `sort.reverse!` is the most performant way. --- array.c | 91 +++++++++++++++++++++++++++++++++++++++++ test/ruby/test_array.rb | 51 +++++++++++++++++++++++ 2 files changed, 142 insertions(+) diff --git a/array.c b/array.c index f8effc9d61..3392cd0c12 100644 --- a/array.c +++ b/array.c @@ -2822,6 +2822,50 @@ rb_ary_sort(VALUE ary) return ary; } +/* + * call-seq: + * ary.reverse_sort -> new_ary + * ary.reverse_sort {|a, b| block} -> new_ary + * + * Returns a new array created by sorting +self+, then reverse it in place. + * + * ary = [ "d", "a", "e", "c", "b" ] + * ary.reverse_sort #=> ["e", "d", "c", "b", "a"] + * ary.reverse_sort {|a, b| b <=> a} #=> ["a", "b", "c", "d", "e"] + * + * The result is not guaranteed to be stable. When the comparison of two + * elements returns +0+, the order of the elements is unpredictable. + * + * See also Array#sort. + */ +static VALUE +rb_ary_reverse_sort(VALUE ary) +{ + return rb_ary_reverse_bang(rb_ary_sort(ary)); +} + +/* + * call-seq: + * ary.reverse_sort! -> ary + * ary.reverse_sort! {|a, b| block} -> ary + * + * Sorts +self+ and reverse it in place. + * + * ary = [ "d", "a", "e", "c", "b" ] + * ary.reverse_sort! #=> ["e", "d", "c", "b", "a"] + * ary.reverse_sort! {|a, b| b <=> a} #=> ["a", "b", "c", "d", "e"] + * + * The result is not guaranteed to be stable. When the comparison of two + * elements returns +0+, the order of the elements is unpredictable. + * + * See also Array#sort! + */ +static VALUE +rb_ary_reverse_sort_bang(VALUE ary) +{ + return rb_ary_reverse_bang(rb_ary_sort_bang(ary)); +} + static VALUE rb_ary_bsearch_index(VALUE ary); /* @@ -2983,6 +3027,49 @@ rb_ary_sort_by_bang(VALUE ary) return ary; } +/* + * call-seq: + * ary.reverse_sort_by {|obj| block} -> ary + * ary.reverse_sort_by -> Enumerator + * + * Returns a new array containing +self+'s elements using a set of keys + * generated by mapping the values in +self+ through the given block, then + * reverse it in place. + * + * The result is not guaranteed to be stable. When two keys are equal, + * the order of the corresponding elements is unpredictable. + * + * If no block is given, an Enumerator is returned instead. + * + * See also Array#sort_by + */ +static VALUE +rb_ary_reverse_sort_by(VALUE ary) +{ + ary = rb_ary_dup(ary); + return rb_ary_reverse_bang(rb_ary_sort_by_bang(ary)); +} + +/* + * call-seq: + * ary.reverse_sort_by! {|obj| block} -> ary + * ary.reverse_sort_by! -> Enumerator + * + * Sorts +self+ in place using a set of keys generated by mapping the + * values in +self+ through the given block, then reverse it in-place. + * + * The result is not guaranteed to be stable. When two keys are equal, + * the order of the corresponding elements is unpredictable. + * + * If no block is given, an Enumerator is returned instead. + * + * See also Array#sort_by! + */ +static VALUE +rb_ary_reverse_sort_by_bang(VALUE ary) +{ + return rb_ary_reverse_bang(rb_ary_sort_by_bang(ary)); +} /* * call-seq: @@ -6836,6 +6923,10 @@ Init_Array(void) rb_define_method(rb_cArray, "join", rb_ary_join_m, -1); rb_define_method(rb_cArray, "reverse", rb_ary_reverse_m, 0); rb_define_method(rb_cArray, "reverse!", rb_ary_reverse_bang, 0); + rb_define_method(rb_cArray, "reverse_sort", rb_ary_reverse_sort, 0); + rb_define_method(rb_cArray, "reverse_sort!", rb_ary_reverse_sort_bang, 0); + rb_define_method(rb_cArray, "reverse_sort_by", rb_ary_reverse_sort_by, 0); + rb_define_method(rb_cArray, "reverse_sort_by!", rb_ary_reverse_sort_by_bang, 0); rb_define_method(rb_cArray, "rotate", rb_ary_rotate_m, -1); rb_define_method(rb_cArray, "rotate!", rb_ary_rotate_bang, -1); rb_define_method(rb_cArray, "sort", rb_ary_sort, 0); diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index b61bac03c2..b9964d96ee 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -1415,6 +1415,57 @@ def test_reverse_each assert_equal(0, i) end + def test_reverse_sort + a = @cls[ 4, 1, 2, 3 ] + assert_equal(@cls[4, 3, 2, 1], a.reverse_sort) + assert_equal(@cls[4, 1, 2, 3], a) + + assert_equal(@cls[4, 3, 2, 1], a.reverse_sort { |x, y| y <=> x} ) + assert_equal(@cls[4, 1, 2, 3], a) + + assert_equal(@cls[4, 3, 2, 1], a.reverse_sort { |x, y| (x - y) * (2**100) }) + + a.fill(1) + assert_equal(@cls[1, 1, 1, 1], a.reverse_sort) + + assert_equal(@cls[], @cls[].reverse_sort) + end + + def test_reverse_sort! + a = @cls[ 4, 1, 2, 3 ] + assert_equal(@cls[4, 3, 2, 1], a.reverse_sort!) + assert_equal(@cls[4, 3, 2, 1], a) + + assert_equal(@cls[1, 2, 3, 4], a.reverse_sort! { |x, y| y <=> x} ) + assert_equal(@cls[1, 2, 3, 4], a) + + a.fill(1) + assert_equal(@cls[1, 1, 1, 1], a.reverse_sort!) + + assert_equal(@cls[1], @cls[1].reverse_sort!) + assert_equal(@cls[], @cls[].reverse_sort!) + + a = @cls[4, 3, 2, 1] + a.reverse_sort! {|m, n| a.replace([9, 8, 7, 6]); m <=> n } + assert_equal([4, 3, 2, 1], a) + + a = @cls[4, 3, 2, 1] + a.reverse_sort! {|m, n| a.replace([9, 8, 7]); m <=> n } + assert_equal([4, 3, 2, 1], a) + end + + def test_reverse_sort_by + a = [1, 3, 5, 2, 4] + assert_equal([1, 2, 3, 4, 5], a.reverse_sort_by {|x| -x }) + assert_equal([1, 3, 4, 2, 4], a) + end + + def test_reverse_sort_by! + a = [1, 3, 5, 2, 4] + a.reverse_sort_by! {|x| -x } + assert_equal([1, 2, 3, 4, 5], a) + end + def test_rindex a = @cls[ 'cat', 99, /a/, 99, [ 1, 2, 3] ] assert_equal(0, a.rindex('cat')) -- 2.21.0