310 votes

Tri d'un tableau en ordre décroissant dans Ruby

J'ai un tableau de hachages comme suit

[
  { :foo => 'foo', :bar => 2 },
  { :foo => 'foo', :bar => 3 },
  { :foo => 'foo', :bar => 5 },
]

Je suis en train de trier tableau ci-dessus dans l'ordre décroissant en fonction de la valeur de :bar dans chacun de hachage.

Je suis l'aide d' sort_by comme suit pour trier tableau ci-dessus.

a.sort_by { |h| h[:bar] }

Toutefois, au-dessus trie le tableau par ordre croissant. Comment puis-je faire de tri dans l'ordre décroissant?

Une solution aurait été de prendre les mesures suivantes:

a.sort_by { |h| -h[:bar] }

Mais qui signe négatif ne me semble pas approprié. Tout point de vue?

613voto

the Tin Man Points 69148

Il est toujours instructif de faire un benchmark sur les différentes réponses proposées. Voici ce que j'ai trouvé:

#!/usr/bin/ruby

exiger "de référence"

ary = []
1000.fois { 
 ary << {:bar => rand(1000)} 
}

n = 500
L'indice de référence.bm(20) do |x|
 x.rapport("tri") { n.fois { ary.tri{ |a,b| b[:bar] < = > [: bar] } } }
 x.rapport("tri inverse") { n.fois { ary.tri{ |a,b| a [bar] <=> b[:bar] }.inverse } }
 x.rapport("sort_by -un [bar]") { n.fois { ary.sort_by{ |a| -a [bar] } } }
 x.rapport("sort_by un [bar]*-1") { n.fois { ary.sort_by{ |un| une [bar]*-1 } } }
 x.rapport("sort_by.inverse!") { n.fois { ary.sort_by{ |un| une [bar] }.inverse } }
fin

 le système de l'utilisateur réel total
trier 3.960000 0.010000 3.970000 ( 3.990886)
tri inverse 4.040000 0.000000 4.040000 ( 4.038849)
sort_by -un [bar] 0.690000 0.000000 0.690000 ( 0.692080)
sort_by un [bar]*-1 0.700000 0.000000 0.700000 ( 0.699735)
sort_by.inverse! 0.650000 0.000000 0.650000 ( 0.654447)

Je pense qu'il est intéressant de noter que @Pablo sort_by{...}.reverse! est la plus rapide. Avant d'exécuter le test, j'ai pensé qu'il serait plus lente que "-a[:bar]" mais la négation de la valeur s'avère prendre plus de temps qu'il n'en faut pour inverser la matrice entière en un seul passage. Ce n'est pas beaucoup de différence, mais chaque petite vitesse-aide.


Veuillez noter que ces résultats sont différents de Ruby 1.9

Voici les résultats pour Ruby 1.9.3p194 (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)

Ces sont sur un vieux MacBook Pro. Plus récente, ou des machines plus rapides, ont de plus faibles valeurs, mais les différences relatives restera.


Ici est un peu la version mise à jour du matériel récent et 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)

93voto

Pablo Fernandez Points 32003

Juste une chose rapide, qui dénote l'intention de l'ordre décroissant.

 descending = -1
a.sort_by { |h| h[:bar] * descending }
 

(Penseront à une meilleure façon dans le temps);)

MODIFIER

 a.sort_by { |h| h[:bar] }.reverse!
 

59voto

JRL Points 36674

Vous pourriez faire:

 a.sort{|a,b| b[:bar] <=> a[:bar]}
 

7voto

OscarRyz Points 82553

Qu'en est-il de:

  a.sort {|x,y| y[:bar]<=>x[:bar]}
 

modifier

Ç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"}]
 

3voto

En ce qui concerne la suite de tests mentionnée, ces résultats sont également valables pour les tableaux triés. sort_by / reverse c'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)
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X