Luôn luôn khai sáng để làm điểm chuẩn cho các câu trả lời được đề xuất khác nhau. Đây là những gì tôi phát hiện ra:
#! / usr / bin / hồng ngọc
yêu cầu 'điểm chuẩn'
ary = []
1000 lần
ary << {: bar => rand (1000)}
}
n = 500
Điểm chuẩn.bm (20) làm | x |
x.report ("sắp xếp") {n.times {ary.sort {| a, b | b [: bar] <=> a [: bar]}}}
x.report ("sắp xếp ngược") {n.times {ary.sort {| a, b | a [: bar] <=> b [: bar]} .reverse}}
x.report ("sort_by -a [: bar]") {n.times {ary.sort_by {| a | -một quán bar] } } }
x.report ("sort_by a [: bar] * - 1") {n.times {ary.sort_by {| a | một [: thanh] * - 1}}}
x.report ("sort_by.reverse!") {n.times {ary.sort_by {| a | một [: bar]} .reverse}}
kết thúc
tổng hệ thống người dùng thực
sắp xếp 3,960000 0,010000 3,970000 (3,990886)
sắp xếp ngược 4.040000 0,000000 4.040000 (4.038849)
sort_by -a [: bar] 0.690000 0.000000 0.690000 (0.692080)
sort_by a [: bar] * - 1 0,700000 0,000000 0,700000 (0,699735)
sort_by.reverse! 0,6500 0,000000 0,650000 (0,654447)
Tôi nghĩ thật thú vị khi @ Pablo sort_by{...}.reverse!
là nhanh nhất. Trước khi chạy thử nghiệm, tôi nghĩ rằng nó sẽ chậm hơn " -a[:bar]
" nhưng việc phủ nhận giá trị hóa ra mất nhiều thời gian hơn để đảo ngược toàn bộ mảng trong một lần. Nó không có nhiều sự khác biệt, nhưng mỗi lần tăng tốc đều giúp ích.
Xin lưu ý rằng những kết quả này khác nhau trong Ruby 1.9
Dưới đây là kết quả cho Ruby 1.9.3p194 (phiên bản 2012-04-20 sửa đổi 35410) [x86_64-darwin10.8.0]:
user system total real
sort 1.340000 0.010000 1.350000 ( 1.346331)
sort reverse 1.300000 0.000000 1.300000 ( 1.310446)
sort_by -a[:bar] 0.430000 0.000000 0.430000 ( 0.429606)
sort_by a[:bar]*-1 0.420000 0.000000 0.420000 ( 0.414383)
sort_by.reverse! 0.400000 0.000000 0.400000 ( 0.401275)
Đây là trên một chiếc MacBook Pro cũ. Máy mới hơn hoặc nhanh hơn sẽ có giá trị thấp hơn, nhưng sự khác biệt tương đối sẽ vẫn còn.
Đây là phiên bản cập nhật một chút trên phần cứng mới hơn và phiên bản 2.1.1 của Ruby:
#!/usr/bin/ruby
require 'benchmark'
puts "Running Ruby #{RUBY_VERSION}"
ary = []
1000.times {
ary << {:bar => rand(1000)}
}
n = 500
puts "n=#{n}"
Benchmark.bm(20) do |x|
x.report("sort") { n.times { ary.dup.sort{ |a,b| b[:bar] <=> a[:bar] } } }
x.report("sort reverse") { n.times { ary.dup.sort{ |a,b| a[:bar] <=> b[:bar] }.reverse } }
x.report("sort_by -a[:bar]") { n.times { ary.dup.sort_by{ |a| -a[:bar] } } }
x.report("sort_by a[:bar]*-1") { n.times { ary.dup.sort_by{ |a| a[:bar]*-1 } } }
x.report("sort_by.reverse") { n.times { ary.dup.sort_by{ |a| a[:bar] }.reverse } }
x.report("sort_by.reverse!") { n.times { ary.dup.sort_by{ |a| a[:bar] }.reverse! } }
end
# >> Running Ruby 2.1.1
# >> n=500
# >> user system total real
# >> sort 0.670000 0.000000 0.670000 ( 0.667754)
# >> sort reverse 0.650000 0.000000 0.650000 ( 0.655582)
# >> sort_by -a[:bar] 0.260000 0.010000 0.270000 ( 0.255919)
# >> sort_by a[:bar]*-1 0.250000 0.000000 0.250000 ( 0.258924)
# >> sort_by.reverse 0.250000 0.000000 0.250000 ( 0.245179)
# >> sort_by.reverse! 0.240000 0.000000 0.240000 ( 0.242340)
Kết quả mới chạy mã trên bằng Ruby 2.2.1 trên Macbook Pro mới hơn. Một lần nữa, những con số chính xác không quan trọng, đó là mối quan hệ của họ:
Running Ruby 2.2.1
n=500
user system total real
sort 0.650000 0.000000 0.650000 ( 0.653191)
sort reverse 0.650000 0.000000 0.650000 ( 0.648761)
sort_by -a[:bar] 0.240000 0.010000 0.250000 ( 0.245193)
sort_by a[:bar]*-1 0.240000 0.000000 0.240000 ( 0.240541)
sort_by.reverse 0.230000 0.000000 0.230000 ( 0.228571)
sort_by.reverse! 0.230000 0.000000 0.230000 ( 0.230040)
Cập nhật cho Ruby 2.7.1 trên MacBook Pro giữa năm 2015:
Running Ruby 2.7.1
n=500
user system total real
sort 0.494707 0.003662 0.498369 ( 0.501064)
sort reverse 0.480181 0.005186 0.485367 ( 0.487972)
sort_by -a[:bar] 0.121521 0.003781 0.125302 ( 0.126557)
sort_by a[:bar]*-1 0.115097 0.003931 0.119028 ( 0.122991)
sort_by.reverse 0.110459 0.003414 0.113873 ( 0.114443)
sort_by.reverse! 0.108997 0.001631 0.110628 ( 0.111532)
... Phương thức đảo ngược không thực sự trả về một mảng đảo ngược - nó trả về một liệt kê chỉ bắt đầu ở cuối và hoạt động ngược.
Nguồn cho Array#reverse
là:
static VALUE
rb_ary_reverse_m(VALUE ary)
{
long len = RARRAY_LEN(ary);
VALUE dup = rb_ary_new2(len);
if (len > 0) {
const VALUE *p1 = RARRAY_CONST_PTR_TRANSIENT(ary);
VALUE *p2 = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(dup) + len - 1;
do *p2-- = *p1++; while (--len > 0);
}
ARY_SET_LEN(dup, RARRAY_LEN(ary));
return dup;
}
do *p2-- = *p1++; while (--len > 0);
đang sao chép các con trỏ vào các phần tử theo thứ tự ngược lại nếu tôi nhớ chính xác C của mình, vì vậy mảng bị đảo ngược.