sort_by使おうよ
僅か30分で3つのバグ - Rubyの落し穴 - — ありえるえりあ
arr = [] arr.push({:x=>1,:y=>1}).push({:x=>2,:y=>2}).push({:x=>1,:y=>9}).push({:x=>5,:y=>0}).push({:x=>1,:y=>3})x要素がプライマリなソートキーで、y要素がセカンダリなソートキーだとして、次のようにソ ート処理を書きました。
sort_byならもっと簡単に書ける。
def sort1(arr) arr.sort do |a,b| next 1 if !a[:x] next -1 if !b[:x] cmp = a[:x]<=>b[:x] if cmp != 0 cmp else next 1 if !a[:y] next -1 if !b[:y] a[:y]<=>b[:y] end end end arr = [ {:x=>1,:y=>1}, {:x=>2,:y=>2}, {:x=>1,:y=>9}, {:x=>5,:y=>0}, {:x=>1,:y=>3} ] arr2 = [ {:x=>nil,:y=>0}, {:x=>1,:y=>nil} ] sort1(arr) # => [{:x=>1, :y=>1}, {:x=>1, :y=>3}, {:x=>1, :y=>9}, {:x=>2, :y=>2}, {:x=>5, :y=>0}] sort1(arr2) # => [{:x=>1, :y=>nil}, {:x=>nil, :y=>0}] # nil=0とみなせばこう。 def sort2(arr) arr.sort_by do |h| [h[:x].to_i, h[:y].to_i] end end sort2(arr) # => [{:x=>1, :y=>1}, {:x=>1, :y=>3}, {:x=>1, :y=>9}, {:x=>2, :y=>2}, {:x=>5, :y=>0}] sort2(arr2) # => [{:x=>nil, :y=>0}, {:x=>1, :y=>nil}] # nilを最後にするならばかでかい値にする。 def sort3(arr) nil_value = 100000000000 arr.sort_by do |h| [h[:x]||nil_value, h[:y]||nil_value] end end sort3(arr) # => [{:x=>1, :y=>1}, {:x=>1, :y=>3}, {:x=>1, :y=>9}, {:x=>2, :y=>2}, {:x=>5, :y=>0}] sort3(arr2) # => [{:x=>1, :y=>nil}, {:x=>nil, :y=>0}] # 重み関数を計算させると爆速。 def sort4(arr) big = 100000000000 arr.sort_by do |h| (h[:x]||big)*big + (h[:x]||big) end end sort4(arr) # => [{:x=>1, :y=>1}, {:x=>1, :y=>3}, {:x=>1, :y=>9}, {:x=>2, :y=>2}, {:x=>5, :y=>0}] sort4(arr2) # => [{:x=>1, :y=>nil}, {:x=>nil, :y=>0}] ary4 = Array.new(3000){ {:x => rand(10), :y => rand(10000)} } require 'benchmark' Benchmark.bmbm do |b| b.report("sort1") { sort1(ary4) } b.report("sort2") { sort2(ary4) } b.report("sort3") { sort3(ary4) } b.report("sort4") { sort4(ary4) } end # >> Rehearsal ----------------------------------------- # >> sort1 0.080000 0.000000 0.080000 ( 0.073833) # >> sort2 0.060000 0.000000 0.060000 ( 0.063894) # >> sort3 0.070000 0.000000 0.070000 ( 0.069434) # >> sort4 0.010000 0.000000 0.010000 ( 0.015070) # >> -------------------------------- total: 0.220000sec # >> # >> user system total real # >> sort1 0.080000 0.000000 0.080000 ( 0.073774) # >> sort2 0.070000 0.000000 0.070000 ( 0.065415) # >> sort3 0.060000 0.000000 0.060000 ( 0.063259) # >> sort4 0.010000 0.000000 0.010000 ( 0.015426)