È sempre illuminante fare un punto di riferimento sulle varie risposte suggerite. Ecco cosa ho scoperto:
#! / Usr / bin / ruby
richiede 'benchmark'
ary = []
1000.times {
ary << {: bar => rand (1000)}
}
n = 500
Benchmark.bm (20) do | 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 | -un 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}}
fine
sistema utente totale reale
ordina 3.960000 0.010000 3.970000 (3.990886)
ordina al contrario 4.040000 0.000000 4.040000 (4.038849)
sort_by -a [: bar] 0.690000 0.000000 0.690000 (0.692080)
ordina_di un [: bar] * - 1 0.700000 0.000000 0.700000 (0.699735)
sort_by.reverse! 0.650000 0.000000 0.650000 (0.654447)
Penso che sia interessante che @ Pablo's sort_by{...}.reverse!
sia il più veloce. Prima di eseguire il test ho pensato che sarebbe stato più lento di " -a[:bar]
" ma negare il valore risulta impiegare più tempo di quanto non faccia per invertire l'intero array in un passaggio. Non fa molta differenza, ma ogni piccola accelerazione aiuta.
Si noti che questi risultati sono diversi in Ruby 1.9
Ecco i risultati per Ruby 1.9.3p194 (revisione 20/04/2012 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)
Questi sono su un vecchio MacBook Pro. Le macchine più recenti o più veloci avranno valori più bassi, ma le differenze relative rimarranno.
Ecco una versione un po 'aggiornata dell'hardware più recente e la versione 2.1.1 di 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)
Nuovi risultati che eseguono il codice sopra usando Ruby 2.2.1 su un Macbook Pro più recente. Ancora una volta, i numeri esatti non sono importanti, sono le loro relazioni:
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)
Aggiornato per Ruby 2.7.1 su un MacBook Pro di metà 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)
... il metodo inverso in realtà non restituisce un array invertito, ma restituisce un enumeratore che inizia alla fine e funziona all'indietro.
La fonte per Array#reverse
è:
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);
sta copiando i puntatori sugli elementi in ordine inverso se ricordo correttamente la mia C, quindi l'array è invertito.