Issue #16022 has been updated by ryanflach (Ryan Flach).


jeremyevans0 (Jeremy Evans) wrote:
> The current behavior is expected and documented: `The result is not guaranteed to be stable. When two keys are equal, the order of the corresponding elements is unpredictable.`
> 
> If you want a stable sort, you could use the approach mentioned in https://8thlight.com/blog/will-warner/2013/03/26/stable-sorting-in-ruby.html

Jeremy,

Thanks for the response. You are definitely correct regarding its documentation. What I was attempting to point out was the apparent predictability in which it is not consistent, in that the first and last elements are swapped, which appears to be reproducible up to a fairly large number of elements in the array (but never at less than 8):
``` ruby
[1] pry(main)> def sorted(start_number, end_number)
[1] pry(main)*   [{a: 1, b: start_number}].tap do |arr|
[1] pry(main)*     ((start_number + 1)...end_number).each do |n|
[1] pry(main)*       arr << {a: 1, b: n}
[1] pry(main)*     end
[1] pry(main)*     arr << {a: 1, b: end_number}
[1] pry(main)*   end.sort_by { |h| h[:a] }
[1] pry(main)* end
=> :sorted
[2] pry(main)> arr = sorted(1, 10_000)
=> [{:a=>1, :b=>10000},
 {:a=>1, :b=>2},
 {:a=>1, :b=>3},
 {:a=>1, :b=>4},
 {:a=>1, :b=>5},
 {:a=>1, :b=>6},
 {:a=>1, :b=>7},
 {:a=>1, :b=>8},
 {:a=>1, :b=>9},
 {:a=>1, :b=>10},
 {:a=>1, :b=>11},
 {:a=>1, :b=>12},
 {:a=>1, :b=>13},
 {:a=>1, :b=>14},
[3] pry(main)> arr.first
=> {:a=>1, :b=>10000}
[4] pry(main)> arr.last
=> {:a=>1, :b=>1}
```
Best,
Ryan


----------------------------------------
Bug #16022: Enumerable#sort_by returns a swapped first and last element when the sort value is identical and collection is >= 8 elements
https://bugs.ruby-lang.org/issues/16022#change-80053

* Author: ryanflach (Ryan Flach)
* Status: Rejected
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: 2.5.5p157
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN
----------------------------------------
**Overview**
I've seen in the source code that the ordering may be unpredictable (https://github.com/ruby/ruby/blob/515e106fb73a1a3bc69b6f1670bbaaebf45fee30/enum.c#L1159-L1160), but it seems to consistently swap the first and last element when there are 8 or more elements.

**Ruby version**
ruby 2.5.5p157 (2019-03-15 revision 67260) [x86_64-darwin18]

**To reproduce:**
``` ruby
[1] pry(main)> [{a: 1, b: 1}, {a: 1, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}, {a: 1, b: 5}, {a: 1, b: 6}, {a: 1, b: 7}, {a: 1, b: 8}].sort_by { |h| h[:a] }
=> [{:a=>1, :b=>8}, {:a=>1, :b=>2}, {:a=>1, :b=>3}, {:a=>1, :b=>4}, {:a=>1, :b=>5}, {:a=>1, :b=>6}, {:a=>1, :b=>7}, {:a=>1, :b=>1}]
[2] pry(main)> [{a: 1, b: 1}, {a: 1, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}, {a: 1, b: 5}, {a: 1, b: 6}, {a: 1, b: 7}].sort_by { |h| h[:a] }
=> [{:a=>1, :b=>1}, {:a=>1, :b=>2}, {:a=>1, :b=>3}, {:a=>1, :b=>4}, {:a=>1, :b=>5}, {:a=>1, :b=>6}, {:a=>1, :b=>7}]

```
I would expect the above to remain in order, when a sort has not actually taken place.




-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>