在Ruby中按降序排序数组

Was*_*eem 266 ruby sorting

我有一系列哈希如下

[
  { :foo => 'foo', :bar => 2 },
  { :foo => 'foo', :bar => 3 },
  { :foo => 'foo', :bar => 5 },
]
Run Code Online (Sandbox Code Playgroud)

我试图根据:bar每个哈希值中的降序对数组进行排序.

我正在使用sort_by如下排序数组.

a.sort_by { |h| h[:bar] }
Run Code Online (Sandbox Code Playgroud)

但是,上面按升序对数组进行排序.如何按降序排序?

一种解决方案是执行以下操作:

a.sort_by { |h| -h[:bar] }
Run Code Online (Sandbox Code Playgroud)

但这个负号似乎不合适.任何意见?

the*_*Man 539

对各种建议的答案进行基准测试总是很有启发性.这是我发现的:

#!/usr/bin/ruby

require '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| -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

                          user     system      total        real
sort                  3.960000   0.010000   3.970000 (  3.990886)
sort reverse          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)

我认为有趣的是@ Pablo sort_by{...}.reverse!是最快的.在运行测试之前,我认为它会慢于" -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)
Run Code Online (Sandbox Code Playgroud)

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


这是有关新硬件和Ruby 2.1.1版本的更新版本:

#!/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)
Run Code Online (Sandbox Code Playgroud)

在更新的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)
Run Code Online (Sandbox Code Playgroud)

  • 超级实用.感谢您的额外努力. (41认同)
  • "当人们提供像这样的基准证据时,我喜欢它!" 我也这样做,因为那时我没有. (25认同)
  • @theTinMan你能提供一个TL; DR为你的答案.所有这些基准信息都非常有用.但TL; DR在答案之上对那些只想要答案的人有用.我知道他们应该阅读整个解释,我认为他们会.仍然是TL; DR将是非常有用的恕我直言.谢谢你的努力. (9认同)
  • 我同意@Waseem.正如这个答案所研究的那样,OP没有问"在Ruby中进行降序排序的最快方法是什么".一个TL;顶部的DR显示简单的用途,然后是基准,将改善这个答案IMO. (8认同)
  • 当人们提供像这样的基准证明时,我喜欢它!真棒! (7认同)
  • TL; DR答案是读取结果.这是需要了解的重要信息,所以无论是浏览它还是研究它,无论哪种方式都可以从中得到它.仅供参考,如果你在我的团队中,如果我认为你撇去它,我会给你一个测试. (4认同)
  • TL;DR 使用 `sort_by().reverse` 或 `.reverse!` 除非你关心内存。 (2认同)

Pab*_*dez 86

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

descending = -1
a.sort_by { |h| h[:bar] * descending }
Run Code Online (Sandbox Code Playgroud)

(会想到更好的方式);)


a.sort_by { |h| h[:bar] }.reverse!
Run Code Online (Sandbox Code Playgroud)

  • 如果你不反向使用爆炸,你将不会反转阵列,而是创建另一个反转的阵列. (3认同)
  • 这适用于数字,但不适用于其他类型的字符串 (3认同)

JRL*_*JRL 52

你可以这样做:

a.sort{|a,b| b[:bar] <=> a[:bar]}
Run Code Online (Sandbox Code Playgroud)

  • 但是使用`sort_by`的全部意义在于它避免了多次运行比较功能 (4认同)
  • -1.`sort_by`效率更高,更易读.否定价值或在最后做反向将更快,更可读. (3认同)

Osc*_*Ryz 6

关于什么:

 a.sort {|x,y| y[:bar]<=>x[:bar]}
Run Code Online (Sandbox Code Playgroud)

有用!!

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"}]
Run Code Online (Sandbox Code Playgroud)


Nik*_*esl 6

我看到我们(除了其他人之外)基本上有两个选择:

a.sort_by { |h| -h[:bar] }
Run Code Online (Sandbox Code Playgroud)

a.sort_by { |h| h[:bar] }.reverse
Run Code Online (Sandbox Code Playgroud)

当排序键是唯一的时,虽然两种方法都能获得相同的结果,但是请记住,该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}]
Run Code Online (Sandbox Code Playgroud)

尽管您通常不需要关心这一点,但有时您会这样做。为避免这种行为,您可以引入第二个排序键(确保至少对于具有相同排序键的所有项目都必须是唯一的):

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}]
Run Code Online (Sandbox Code Playgroud)