Itu selalu mencerahkan untuk melakukan tolok ukur pada berbagai jawaban yang disarankan. Inilah yang saya temukan:
#! / usr / bin / ruby
membutuhkan 'tolok ukur'
ary = []
1000.kali {
ary << {: bar => rand (1000)}
}
n = 500
Benchmark.bm (20) lakukan | x |
x.report ("sort") {n.times {ary.sort {| a, b | b [: bar] <=> a [: bar]}}}
x.report ("sort reverse") {n.times {ary.sort {| a, b | a [: bar] <=> b [: bar]} .reverse}}
x.report ("sort_by -a [: bar]") {n.times {ary.sort_by {| a | -sebuah bar] } } }
x.report ("sort_by a [: bar] * - 1") {n.times {ary.sort_by {| a | a [: bar] * - 1}}}
x.report ("sort_by.reverse!") {n.times {ary.sort_by {| a | a [: bar]} .reverse}}
akhir
total sistem pengguna nyata
sortir 3.960000 0.010000 3.970000 (3.990886)
sortir mundur 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,650000 0,000000 0,650000 (0,654447)
Saya pikir ini menarik bahwa @ Pablo's sort_by{...}.reverse!
tercepat. Sebelum menjalankan tes saya pikir ini akan lebih lambat daripada " -a[:bar]
" tetapi meniadakan nilainya ternyata membutuhkan waktu lebih lama daripada membalik seluruh array dalam satu lintasan. Tidak banyak perbedaan, tetapi setiap percepatan kecil membantu.
Harap dicatat bahwa hasil ini berbeda di Ruby 1.9
Berikut adalah hasil untuk Ruby 1.9.3p194 (2012-04-20 revisi 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)
Ini ada di MacBook Pro lama. Mesin yang lebih baru, atau yang lebih cepat, akan memiliki nilai yang lebih rendah, tetapi perbedaan relatif akan tetap ada.
Berikut ini adalah versi yang sedikit diperbarui pada perangkat keras yang lebih baru dan versi 2.1.1 dari 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)
Hasil baru menjalankan kode di atas menggunakan Ruby 2.2.1 pada Macbook Pro yang lebih baru. Sekali lagi, angka pastinya tidak penting, ini adalah hubungan mereka:
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)
Diperbarui untuk Ruby 2.7.1 pada Mid-2015 MacBook Pro:
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)
... metode terbalik sebenarnya tidak mengembalikan array yang terbalik - metode ini mengembalikan enumerator yang baru saja dimulai di akhir dan bekerja mundur.
Sumbernya Array#reverse
adalah:
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);
menyalin pointer ke elemen dalam urutan terbalik jika saya ingat C saya dengan benar, sehingga array dibalik.