Siempre es esclarecedor hacer un punto de referencia en las diferentes respuestas sugeridas. Esto es lo que descubrí:
#! / usr / bin / ruby
requiere 'punto de referencia'
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 ("ordenar al revés") {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 [: barra] * - 1}}}
x.report ("sort_by.reverse!") {n.times {ary.sort_by {| a | a [: bar]} .reverse}}
final
sistema de usuario total real
ordenar 3.960000 0.010000 3.970000 (3.990886)
ordenar inverso 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)
Creo que es interesante que @ Pablo's sort_by{...}.reverse!
sea el más rápido. Antes de ejecutar la prueba, pensé que sería más lento que " -a[:bar]
", pero negar el valor lleva más tiempo que invertir la matriz completa en una sola pasada. No es una gran diferencia, pero cada pequeña aceleración ayuda.
Tenga en cuenta que estos resultados son diferentes en Ruby 1.9
Estos son los resultados para Ruby 1.9.3p194 (2012-04-20 revisión 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)
Estos están en un viejo MacBook Pro. Las máquinas más nuevas o más rápidas tendrán valores más bajos, pero las diferencias relativas permanecerán.
Aquí hay una versión un poco actualizada en el hardware más nuevo y la versión 2.1.1 de 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)
Nuevos resultados ejecutando el código anterior usando Ruby 2.2.1 en un Macbook Pro más reciente. Una vez más, los números exactos no son importantes, son sus relaciones:
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)
Actualizado para Ruby 2.7.1 en una MacBook Pro de mediados 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)
... el método inverso en realidad no devuelve una matriz inversa: devuelve un enumerador que solo comienza al final y funciona al revés.
La fuente Array#reverse
es:
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 los punteros a los elementos en orden inverso si recuerdo mi C correctamente, por lo que la matriz se invierte.