在Ruby中按降序对数组进行sorting

我有一个像下面哈希arrays

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

我想按照每个散列中的:bar的值降序排列上面的数组。

我正在使用sort_by像以下sorting上面的数组。

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

但是,上面按升序对数组进行sorting。 我如何使它按降序sorting?

一个解决scheme是做以下事情:

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

但是这个负面的迹象似乎并不合适。 任何意见?

对各种build议的答案做一个基准总是很有启发性的。 这是我发现的:

 #!的/ usr / bin中/ruby

要求“基准”

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

 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 |  -一间酒吧] } } }
   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}}
结束

                          用户系统总数真实
sorting3.960000 0.010000 3.970000(3.990886)
sorting反向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)

我认为有趣的是sort_by{...}.reverse!sort_by{...}.reverse! 是最快的。 在运行testing之前,我认为它会比“ -a[:bar] ”慢,但是否定的结果会花费比在一遍中反转整个数组更长的时间。 这没什么区别,但每一个小小的加速都有帮助。


请注意,这些结果在Ruby 1.9中是不同的

以下是Ruby 1.9.3p194(2012-04-20修订版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) 

这些在旧的MacBook Pro上。 较新的或较快的机器将具有较低的值,但相对差异将保持不变。


以下是更新的硬件和2.1.1版本的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) 

在更新的Macbook Pro上使用Ruby 2.2.1运行上述代码的新结果。 再次,确切的数字并不重要,这是他们的关系:

 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) 

只是一个快速的事情,这表示降序的意图。

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

(同时会想到更好的方法);)


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

你可以这样做:

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

关于什么:

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

有用!!

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

关于提到的基准套件…这些结果也适用于sorting的数组。 sort_by / reverse是:)

例如:

 # 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 

结果是:

 $: 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) 

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

我看到我们有(其他人)基本上有两个select:

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

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

虽然这两种方式给你相同的结果,当你的sorting键是唯一的,请记住, reverse方式将颠倒相同的键的顺序

例:

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

虽然你经常不需要关心这个,但有时候你会这么做。 为了避免这种行为,你可以引入第二个sorting键(至less对于具有相同sorting键的所有项目来说,这肯定是唯一的):

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