Ruby で 2 つの配列の並べ替え方法を学びました。
array = ["one", "two", "three"]
array.sort.reverse!
また:
array = ["one", "two", "three"]
array.sort { |x,y| y<=>x }
そして、私は2つを区別することができません。どちらの方法が優れており、実行の違いは正確にはどれですか?
ここには本当に違いはありません。どちらのメソッドも新しい配列を返します。
この例では、単純であるほど優れています。array.sort.reverse
代替案よりもはるかに読みやすいため、お勧めします。メソッドへのブロックの受け渡しsort
は、より複雑なデータ構造とユーザー定義クラスの配列のために保存する必要があります。
編集:メソッド (! で終わるものはすべて) はパフォーマンス ゲームに適していますが、更新された配列を返す必要destructive
がないことが指摘されました。を返す可能性が非常に高いため、これを覚えておくことが重要です。新しく生成された配列で破壊的なメソッドを使用したい場合は、ワンライナーではなく別の行で呼び出すことをお勧めします。array.sort.reverse!
nil
.reverse!
例:
array = array.sort
array.reverse!
に優先する必要があります
array = array.sort.reverse!
多くの場合、ベンチマークに代わるものはありません。短いスクリプトではおそらく違いはありませんが、#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
システムは #reverse! と報告します。結合比較演算子を使用する場合のほぼ 2 倍の速さです。
user system total real
reverse! 0.340000 0.000000 0.340000 ( 0.344198)
spaceship 0.590000 0.010000 0.600000 ( 0.595747)
私のアドバイス:タイトなループで実行していない限り、特定のコンテキストで意味的に意味のある方を使用してください。
私のマシンで tessi のベンチマークを試してみると、いくつかの興味深い結果が得られました。ruby 2.0.0p195 [x86_64-darwin12.3.0]
OS X システムで Ruby 2 の最新リリースを実行しています。Benchmark モジュールではなく、bmbmを使用しました。bm
私のタイミングは次のとおりです。
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)
まず、リハーサル フェーズではsort!
、比較ブロックを使用すると明らかに勝者になることに注意してください。Matz は Ruby 2 でそれを徹底的に調整したに違いありません!
私が非常に奇妙に感じたもう 1 つのことは、プロダクション パスでどの程度の改善array.sort.reverse!
と展示が行われたかということです。array.sort!.reverse!
非常に極端だったので、既にソートされたこれらのデータを何らかの形で台無しにして渡したかどうか疑問に思ったので、各ベンチマークを実行する前に、ソート済みデータまたは逆ソート済みデータの明示的なチェックを追加しました。
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