在 Ruby 中对字符串数组进行排序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16637869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sorting an array of strings in Ruby
提问by poorvank
I have learned two array sorting methods in Ruby:
我在Ruby中学习了两种数组排序方法:
array = ["one", "two", "three"]
array.sort.reverse!
or:
或者:
array = ["one", "two", "three"]
array.sort { |x,y| y<=>x }
And I am not able to differentiate between the two. Which method is better and how exactly are they different in execution?
我无法区分这两者。哪种方法更好,它们在执行上究竟有何不同?
回答by tessi
Both lines do the same (create a new array, which is reverse sorted). The main argument is about readability and performance. array.sort.reverse!is more readable than array.sort{|x,y| y<=>x}- I think we can agree here.
两行都做同样的事情(创建一个新的数组,它是反向排序的)。主要论点是关于可读性和性能。array.sort.reverse!比array.sort{|x,y| y<=>x}- 我认为我们可以在这里达成一致。
For the performance part, I created a quick benchmark script, which gives the following on my system (ruby 1.9.3p392 [x86_64-linux]):
对于性能部分,我创建了一个快速基准测试脚本,它在我的系统 ( ruby 1.9.3p392 [x86_64-linux])上给出了以下内容:
user system total real
array.sort.reverse 1.330000 0.000000 1.330000 ( 1.334667)
array.sort.reverse! 1.200000 0.000000 1.200000 ( 1.198232)
array.sort!.reverse! 1.200000 0.000000 1.200000 ( 1.199296)
array.sort{|x,y| y<=>x} 5.220000 0.000000 5.220000 ( 5.239487)
Run times are pretty constant for multiple executions of the benchmark script.
对于基准脚本的多次执行,运行时间是相当恒定的。
array.sort.reverse(with or without !) is way faster than array.sort{|x,y| y<=>x}. Thus, I recommend that.
array.sort.reverse(有或没有!)比array.sort{|x,y| y<=>x}. 因此,我建议这样做。
Here is the script as a Reference:
这是脚本作为参考:
#!/usr/bin/env ruby
require 'benchmark'
Benchmark.bm do|b|
master = (1..1_000_000).map(&:to_s).shuffle
a = master.dup
b.report("array.sort.reverse ") do
a.sort.reverse
end
a = master.dup
b.report("array.sort.reverse! ") do
a.sort.reverse!
end
a = master.dup
b.report("array.sort!.reverse! ") do
a.sort!.reverse!
end
a = master.dup
b.report("array.sort{|x,y| y<=>x} ") do
a.sort{|x,y| y<=>x}
end
end
回答by James Brewer
There really is no difference here. Both methods return a new array.
这里真的没有区别。这两种方法都返回一个新数组。
For the purposes of this example, simpler is better. I would recommend array.sort.reversebecause it is much more readable than the alternative. Passing blocks to methods like sortshould be saved for arrays of more complex data structures and user-defined classes.
就本示例而言,越简单越好。我会推荐,array.sort.reverse因为它比替代方案更具可读性。将块传递给方法,例如sort应该为更复杂的数据结构和用户定义的类的数组保存。
Edit: While destructivemethods (anything ending in a !) are good for performance games, it was pointed out that they aren't requiredto return an updated array, or anything at all for that matter. It is important to keep this in mind because array.sort.reverse!could very likely return nil. If you wish to use a destructive method on a newly generated array, you should prefer calling .reverse!on a separate line instead of having a one-liner.
编辑:虽然destructive方法(任何以 ! 结尾的东西)对性能游戏都有好处,但有人指出它们不需要返回更新的数组,或者根本不需要返回任何东西。记住这array.sort.reverse!一点很重要,因为很可能会返回nil。如果您希望在新生成的数组上使用破坏性方法,您应该更喜欢.reverse!在单独的行上调用而不是单行。
Example:
例子:
array = array.sort
array.reverse!
should be preferred to
应该优先
array = array.sort.reverse!
回答by Todd A. Jacobs
Reverse! is Faster
逆转!是比较快的
There's often no substitute for benchmarking. While it probably makes no difference in shorter scripts, the #reverse! method is significantly faster than sorting using the "spaceship" operator. For example, on MRI Ruby 2.0, and given the following benchmark code:
基准测试通常是无可替代的。虽然它在较短的脚本中可能没有区别,但 #reverse! 方法比使用“宇宙飞船”运算符进行排序要快得多。例如,在 MRI Ruby 2.0 上,并给出以下基准代码:
require 'benchmark'
array = ["one", "two", "three"]
loops = 1_000_000
Benchmark.bmbm do |bm|
bm.report('reverse!') { loops.times {array.sort.reverse!} }
bm.report('spaceship') { loops.times {array.sort {|x,y| y<=>x} }}
end
the system reports that #reverse! is almost twice as fast as using the combined comparison operator.
系统报告#reverse!几乎是使用组合比较运算符的两倍。
user system total real
reverse! 0.340000 0.000000 0.340000 ( 0.344198)
spaceship 0.590000 0.010000 0.600000 ( 0.595747)
My advice: use whichever is more semantically meaningful in a given context, unless you're running in a tight loop.
我的建议是:在给定的上下文中使用语义上更有意义的那个,除非你在一个紧密的循环中运行。
回答by pjs
In playing with tessi's benchmarks on my machine, I've gotten some interesting results. I'm running ruby 2.0.0p195 [x86_64-darwin12.3.0], i.e., latest release of Ruby 2 on an OS X system. I used bmbmrather than bmfrom the Benchmark module. My timings are:
在我的机器上玩 tessi 的基准测试时,我得到了一些有趣的结果。我在ruby 2.0.0p195 [x86_64-darwin12.3.0]OS X 系统上运行,即最新版本的 Ruby 2。我使用bmbm而不是bm来自 Benchmark 模块。我的时间是:
Rehearsal -------------------------------------------------------------
array.sort.reverse: 1.010000 0.000000 1.010000 ( 1.020397)
array.sort.reverse!: 0.810000 0.000000 0.810000 ( 0.808368)
array.sort!.reverse!: 0.800000 0.010000 0.810000 ( 0.809666)
array.sort{|x,y| y<=>x}: 0.300000 0.000000 0.300000 ( 0.291002)
array.sort!{|x,y| y<=>x}: 0.100000 0.000000 0.100000 ( 0.105345)
---------------------------------------------------- total: 3.030000sec
user system total real
array.sort.reverse: 0.210000 0.000000 0.210000 ( 0.208378)
array.sort.reverse!: 0.030000 0.000000 0.030000 ( 0.027746)
array.sort!.reverse!: 0.020000 0.000000 0.020000 ( 0.020082)
array.sort{|x,y| y<=>x}: 0.110000 0.000000 0.110000 ( 0.107065)
array.sort!{|x,y| y<=>x}: 0.110000 0.000000 0.110000 ( 0.105359)
First, note that in the Rehearsal phase that sort!using a comparison block comes in as the clear winner. Matz must have tuned the heck out of it in Ruby 2!
首先,请注意在排练阶段,sort!使用比较块是明显的赢家。Matz 一定是在 Ruby 2 中彻底解决了这个问题!
The other thing that I found exceedingly weird was how much improvement array.sort.reverse!and array.sort!.reverse!exhibited in the production pass. It was so extreme it made me wonder whether I had somehow screwed up and passed these already sorted data, so I added explicit checks for sorted or reverse-sorted data prior to performing each benchmark.
我发现的另一件非常奇怪的事情是在生产阶段中有多少改进array.sort.reverse!和array.sort!.reverse!展示。它是如此极端,让我怀疑我是否以某种方式搞砸并传递了这些已经排序的数据,因此我在执行每个基准测试之前添加了对排序或反向排序数据的显式检查。
My variant of tessi's script follows:
我的 tessi 脚本变体如下:
#!/usr/bin/env ruby
require 'benchmark'
class Array
def sorted?
(1...length).each {|i| return false if self[i] < self[i-1] }
true
end
def reversed?
(1...length).each {|i| return false if self[i] > self[i-1] }
true
end
end
master = (1..1_000_000).map(&:to_s).shuffle
Benchmark.bmbm(25) do|b|
a = master.dup
puts "uh-oh!" if a.sorted?
puts "oh-uh!" if a.reversed?
b.report("array.sort.reverse:") { a.sort.reverse }
a = master.dup
puts "uh-oh!" if a.sorted?
puts "oh-uh!" if a.reversed?
b.report("array.sort.reverse!:") { a.sort.reverse! }
a = master.dup
puts "uh-oh!" if a.sorted?
puts "oh-uh!" if a.reversed?
b.report("array.sort!.reverse!:") { a.sort!.reverse! }
a = master.dup
puts "uh-oh!" if a.sorted?
puts "oh-uh!" if a.reversed?
b.report("array.sort{|x,y| y<=>x}:") { a.sort{|x,y| y<=>x} }
a = master.dup
puts "uh-oh!" if a.sorted?
puts "oh-uh!" if a.reversed?
b.report("array.sort!{|x,y| y<=>x}:") { a.sort!{|x,y| y<=>x} }
end
回答by sawa
With comparison as simple as your example, there is not much difference, but as the formula for comparison gets complicated, it is better to avoid using <=>with a block because the block you pass will be evaluated for each element of the array, causing redundancy. Consider this:
与您的示例一样简单的比较,没有太大区别,但是随着比较公式变得复杂,最好避免使用<=>块,因为您传递的块将针对数组的每个元素进行评估,从而导致冗余。考虑一下:
array.sort{|x, y| some_expensive_method(x) <=> some_expensive_method(y)}
In this case, some_expensive_methodwill be evaluated for each possible pair of element of array.
在这种情况下,some_expensive_method将针对 的每个可能的元素对进行评估array。
In your particular case, use of a block with <=>can be avoided with reverse.
在您的特定情况下,<=>可以避免使用块with reverse。
array.sort_by{|x| some_expensive_method(x)}.reverse
This is called Schwartzian transform.
这称为施瓦兹变换。

