25

Ruby で 2 つの配列の並べ替え方法を学びました。

array = ["one", "two", "three"]
array.sort.reverse!

また:

array = ["one", "two", "three"]
array.sort { |x,y| y<=>x }

そして、私は2つを区別することができません。どちらの方法が優れており、実行の違いは正確にはどれですか?

4

5 に答える 5

7

ここには本当に違いはありません。どちらのメソッドも新しい配列を返します。

この例では、単純であるほど優れています。array.sort.reverse代替案よりもはるかに読みやすいため、お勧めします。メソッドへのブロックの受け渡しsortは、より複雑なデータ構造とユーザー定義クラスの配列のために保存する必要があります。

編集:メソッド (! で終わるものはすべて) はパフォーマンス ゲームに適していますが、更新された配列を返す必要destructiveがないことが指摘されました。を返す可能性が非常に高いため、これを覚えておくことが重要です。新しく生成された配列で破壊的なメソッドを使用したい場合は、ワンライナーではなく別の行で呼び出すことをお勧めします。array.sort.reverse!nil.reverse!

例:

array = array.sort
array.reverse!

に優先する必要があります

array = array.sort.reverse!
于 2013-05-19T18:17:11.893 に答える
3

逆行する!速いです

多くの場合、ベンチマークに代わるものはありません。短いスクリプトではおそらく違いはありませんが、#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)

私のアドバイス:タイトなループで実行していない限り、特定のコンテキストで意味的に意味のある方を使用してください。

于 2013-05-19T18:53:11.437 に答える
2

私のマシンで 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
于 2013-05-20T03:03:50.560 に答える