J'ai un tableau de hachages comme suit
[
{ :foo => 'foo', :bar => 2 },
{ :foo => 'foo', :bar => 3 },
{ :foo => 'foo', :bar => 5 },
]
J'essaie de trier le tableau ci-dessus dans l'ordre décroissant en fonction de la valeur de :bar
dans chaque hachage.
J'utilise sort_by
comme suit pour trier le tableau ci-dessus.
a.sort_by { |h| h[:bar] }
Cependant, ci-dessus, le tableau est trié par ordre croissant. Comment puis-je le trier par ordre décroissant?
Une solution consistait à faire ce qui suit:
a.sort_by { |h| -h[:bar] }
Mais ce signe négatif ne semble pas approprié. Des vues?
Il est toujours intéressant de faire un point de repère sur les différentes réponses suggérées. Voici ce que j'ai découvert:
#!/usr/bin/Ruby nécessite un "repère" ary = [] 1000. fois { << <<: bar => Rand (1000)} } n = 500 Indice de référence.bm (20) do | x | x.report ("sort") {n.times {ary.sort {| a, b | b [: barre] <=> a [: barre]}}} x.report ("sorte de tri inverse") {n.times {ary.sort {| a, b | a [: bar] <=> b [: bar]} .reverse}} x.report ("sort_by -a [: bar]") {n.times {ary.sort_by {| a | -a [: 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}} end total du système utilisateur réel trié 3.960000 0.010000 3.970000 (3.990886) trié inversé 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. sens inverse! 0,650000 0,000000 0,650000 (0,654447)
Je trouve intéressant que le sort_by{...}.reverse!
de @ Pablo soit le plus rapide. Avant d'exécuter le test, je pensais que ce serait plus lent que "-a[:bar]
", mais l'annulation de la valeur prend plus de temps que celle nécessaire pour inverser le tableau en entier en une seule passe. La différence n’est pas grande, mais chaque petite accélération est utile.
Veuillez noter que ces résultats sont différents dans Ruby 1.9
Voici les résultats de Ruby 1.9.3p194 (révision 2012-04-20, révision 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)
Ce sont sur un ancien MacBook Pro. Les machines les plus récentes ou les plus rapides auront des valeurs plus faibles, mais les différences relatives resteront.
Voici une version légèrement mise à jour du nouveau matériel et de la version 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)
Nouveaux résultats exécutant le code ci-dessus à l'aide de Ruby 2.2.1 sur un Macbook Pro plus récent. Encore une fois, les chiffres exacts ne sont pas importants, ce sont leurs relations:
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)
Juste une chose rapide, cela dénote l'intention de l'ordre décroissant.
descending = -1
a.sort_by { |h| h[:bar] * descending }
(Pensera à un meilleur moyen entre temps);)
a.sort_by { |h| h[:bar] }.reverse!
Vous pourriez faire:
a.sort{|a,b| b[:bar] <=> a[:bar]}
Qu'en est-il de:
a.sort {|x,y| y[:bar]<=>x[:bar]}
Ça marche!!
irb
>> a = [
?> { :foo => 'foo', :bar => 2 },
?> { :foo => 'foo', :bar => 3 },
?> { :foo => 'foo', :bar => 5 },
?> ]
=> [{:bar=>2, :foo=>"foo"}, {:bar=>3, :foo=>"foo"}, {:bar=>5, :foo=>"foo"}]
>> a.sort {|x,y| y[:bar]<=>x[:bar]}
=> [{:bar=>5, :foo=>"foo"}, {:bar=>3, :foo=>"foo"}, {:bar=>2, :foo=>"foo"}]
Je vois que nous avons (à côté des autres) essentiellement deux options:
a.sort_by { |h| -h[:bar] }
et
a.sort_by { |h| h[:bar] }.reverse
Bien que les deux méthodes donnent le même résultat lorsque votre clé de tri est unique, n'oubliez pas que la méthode reverse
va inverser l'ordre des clés identiques.
Exemple:
a = [{foo: 1, bar: 1},{foo: 2,bar: 1}]
a.sort_by {|h| -h[:bar]}
=> [{:foo=>1, :bar=>1}, {:foo=>2, :bar=>1}]
a.sort_by {|h| h[:bar]}.reverse
=> [{:foo=>2, :bar=>1}, {:foo=>1, :bar=>1}]
Bien que vous n’ayez souvent pas besoin de vous en soucier, vous le faites parfois. Pour éviter un tel comportement, vous pouvez introduire une deuxième clé de tri (qui doit bien sûr être unique, du moins pour tous les éléments ayant la même clé de tri):
a.sort_by {|h| [-h[:bar],-h[:foo]]}
=> [{:foo=>2, :bar=>1}, {:foo=>1, :bar=>1}]
a.sort_by {|h| [h[:bar],h[:foo]]}.reverse
=> [{:foo=>2, :bar=>1}, {:foo=>1, :bar=>1}]
En ce qui concerne la suite de références mentionnée ..., ces résultats sont également valables pour les tableaux triés. sort_by/reverse it est :)
Par exemple:
# foo.rb
require 'benchmark'
NUM_RUNS = 1000
# arr = []
arr1 = 3000.times.map { { num: Rand(1000) } }
arr2 = 3000.times.map { |n| { num: n } }.reverse
Benchmark.bm(20) do |x|
{ 'randomized' => arr1,
'sorted' => arr2 }.each do |label, arr|
puts '---------------------------------------------------'
puts label
x.report('sort_by / reverse') {
NUM_RUNS.times { arr.sort_by { |h| h[:num] }.reverse }
}
x.report('sort_by -') {
NUM_RUNS.times { arr.sort_by { |h| -h[:num] } }
}
end
end
Et les résultats:
$: Ruby foo.rb
user system total real
---------------------------------------------------
randomized
sort_by / reverse 1.680000 0.010000 1.690000 ( 1.682051)
sort_by - 1.830000 0.000000 1.830000 ( 1.830359)
---------------------------------------------------
sorted
sort_by / reverse 0.400000 0.000000 0.400000 ( 0.402990)
sort_by - 0.500000 0.000000 0.500000 ( 0.499350)
La solution simple ascendante décroissante et inversement est la suivante:
CHAÎNES
str = ['ravi', 'aravind', 'joker', 'poker']
asc_string = str.sort # => ["aravind", "joker", "poker", "ravi"]
asc_string.reverse # => ["ravi", "poker", "joker", "aravind"]
CHIFFRES
digit = [234,45,1,5,78,45,34,9]
asc_digit = digit.sort # => [1, 5, 9, 34, 45, 45, 78, 234]
asc_digit.reverse # => [234, 78, 45, 45, 34, 9, 5, 1]
Pour ceux qui aiment mesurer la vitesse en IPS;)
require 'benchmark/ips'
ary = []
1000.times {
ary << {:bar => Rand(1000)}
}
Benchmark.ips do |x|
x.report("sort") { ary.sort{ |a,b| b[:bar] <=> a[:bar] } }
x.report("sort reverse") { ary.sort{ |a,b| a[:bar] <=> b[:bar] }.reverse }
x.report("sort_by -a[:bar]") { ary.sort_by{ |a| -a[:bar] } }
x.report("sort_by a[:bar]*-1") { ary.sort_by{ |a| a[:bar]*-1 } }
x.report("sort_by.reverse!") { ary.sort_by{ |a| a[:bar] }.reverse }
x.compare!
end
Et des résultats:
Warming up --------------------------------------
sort 93.000 i/100ms
sort reverse 91.000 i/100ms
sort_by -a[:bar] 382.000 i/100ms
sort_by a[:bar]*-1 398.000 i/100ms
sort_by.reverse! 397.000 i/100ms
Calculating -------------------------------------
sort 938.530 (± 1.8%) i/s - 4.743k in 5.055290s
sort reverse 901.157 (± 6.1%) i/s - 4.550k in 5.075351s
sort_by -a[:bar] 3.814k (± 4.4%) i/s - 19.100k in 5.019260s
sort_by a[:bar]*-1 3.732k (± 4.3%) i/s - 18.706k in 5.021720s
sort_by.reverse! 3.928k (± 3.6%) i/s - 19.850k in 5.060202s
Comparison:
sort_by.reverse!: 3927.8 i/s
sort_by -a[:bar]: 3813.9 i/s - same-ish: difference falls within error
sort_by a[:bar]*-1: 3732.3 i/s - same-ish: difference falls within error
sort: 938.5 i/s - 4.19x slower
sort reverse: 901.2 i/s - 4.36x slower