É sempre esclarecedor fazer uma referência nas várias respostas sugeridas. Aqui está o que eu descobri:
#! / usr / bin / ruby
requer 'referência'
ary = []
1000.times {
ary << {: bar => rand (1000)}
}
n = 500
Referência.bm (20) do | x |
x.report ("sort") {n.times {ary.sort {| a, b | b [: bar] <=> a [: bar]}}}
x.report ("ordem inversa") {n.times {ary.sort {| a, b | a [: bar] <=> b [: bar]} .reverse}}
x.report ("sort_by -a [: bar]") {n.times {ary.sort_by {| a | -um 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}}
fim
total do sistema do usuário real
ordenar 3.960000 0.010000 3.970000 (3.990886)
ordem inversa 4.040000 0.000000 4.040000 (4.038849)
sort_by -a [: bar] 0,690000 0,000000 0,690000 (0,692080)
class_by a [: bar] * - 1 0,700000 0,000000 0,700000 (0,699735)
sort_by.reverse! 0,650000 0,000000 0,650000 (0,654447)
Acho interessante que o @ Pablo's sort_by{...}.reverse!
seja o mais rápido. Antes de executar o teste, pensei que seria " -a[:bar]
" mais lento que " ", mas negar o valor leva mais tempo do que o necessário para reverter toda a matriz de uma só vez. Não faz muita diferença, mas cada pequena aceleração ajuda.
Observe que esses resultados são diferentes no Ruby 1.9
Aqui estão os resultados para Ruby 1.9.3p194 (revisão em 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)
Estes estão em um MacBook Pro antigo. Máquinas mais novas ou mais rápidas terão valores mais baixos, mas as diferenças relativas permanecerão.
Aqui está uma versão um pouco atualizada no hardware mais recente e na versão 2.1.1 do 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)
Novos resultados executando o código acima usando o Ruby 2.2.1 em um Macbook Pro mais recente. Novamente, os números exatos não são importantes, são os relacionamentos deles:
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)
Atualizado para Ruby 2.7.1 em um MacBook Pro de meados de 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)
... o método reverso não retorna um array invertido - ele retorna um enumerador que apenas inicia no final e trabalha para trás.
A fonte para 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);
está copiando os ponteiros para os elementos na ordem inversa, se eu me lembrar corretamente do meu C, para que a matriz seja invertida.