Es ist immer aufschlussreich, einen Benchmark für die verschiedenen vorgeschlagenen Antworten durchzuführen. Folgendes habe ich herausgefunden:
#! / usr / bin / ruby
erfordern '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 | -eine 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}}
Ende
Benutzersystem total real
sort 3.960000 0.010000 3.970000 (3.990886)
Umkehrung sortieren 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)
Ich finde es interessant, dass @ Pablo's sort_by{...}.reverse!
am schnellsten ist. Vor dem Ausführen des Tests dachte ich, es wäre langsamer als " -a[:bar]
", aber das Negieren des Werts dauert länger als das Umkehren des gesamten Arrays in einem Durchgang. Es ist kein großer Unterschied, aber jede kleine Beschleunigung hilft.
Bitte beachten Sie, dass diese Ergebnisse in Ruby 1.9 unterschiedlich sind
Hier sind die Ergebnisse für Ruby 1.9.3p194 (2012-04-20 Revision 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)
Diese befinden sich auf einem alten MacBook Pro. Neuere oder schnellere Maschinen haben niedrigere Werte, aber die relativen Unterschiede bleiben bestehen.
Hier ist eine etwas aktualisierte Version auf neuerer Hardware und der 2.1.1-Version von 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)
Neue Ergebnisse beim Ausführen des obigen Codes mit Ruby 2.2.1 auf einem neueren Macbook Pro. Auch hier sind die genauen Zahlen nicht wichtig, es sind ihre Beziehungen:
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)
Aktualisiert für Ruby 2.7.1 auf einem MacBook Pro Mitte 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)
... die umgekehrte Methode gibt kein umgekehrtes Array zurück - sie gibt einen Enumerator zurück, der erst am Ende beginnt und rückwärts arbeitet.
Die Quelle für Array#reverse
ist:
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);
kopiert die Zeiger in umgekehrter Reihenfolge auf die Elemente, wenn ich mich richtig an mein C erinnere, sodass das Array umgekehrt ist.