下面是看一下<=>
做什麼的一些簡單的直觀方式,以及如何顛倒比較變量的順序會影響輸出的順序。
與基本陣列開始:
foo = %w[a z b x]
我們可以做一個升序排序:
foo.sort { |i, j| i <=> j } # => ["a", "b", "x", "z"]
或者通過顛倒兩個變量降序排序進行比較:
foo.sort { |i, j| j <=> i } # => ["z", "x", "b", "a"]
<=>
運算符返回-1,0或1,具體取決於比較結果分別爲<
,==
或>
。
我們可以通過否定比較的結果來進行測試,如果理論成立的話,將會顛倒順序。
foo.sort { |i, j| -(i <=> j) } # => ["z", "x", "b", "a"]
foo.sort { |i, j| -(j <=> i) } # => ["a", "b", "x", "z"]
通過否定比較的結果,順序反轉。但是,爲了使代碼清晰,只需顛倒變量的順序即可。
這一切都說,使用sort
或其破壞性的兄弟sort!
,並不總是排序複雜對象的最快方法。簡單的對象,如字符串和字符以及數字,排序非常快,因爲它們的類實現了快速執行<=>
測試的必要方法。
一些答案和評論提到sort_by
,所以我們去那裏吧。
複雜對象通常不會正確排序,因此我們最終使用getters/accessors來檢索某些我們想要比較的值,並且該操作在CPU時間中有成本。 sort
反覆比較這些值,以便重複進行檢索,並且在沒有發生排序時將其合併爲浪費的時間。
爲了解決這個問題,一位名叫Randall Schwartz的聰明人開始使用算法,該算法預先計算一次用於排序的值;結果,該算法通常被稱爲Schwartzian Transform。該值和實際對象一起捆綁在一個小的子數組中,然後進行排序。由於排序是針對預先計算的值進行的,因此它及其關聯的對象將在排序中移動,直到排序完成。此時,實際的對象被檢索並作爲該方法的結果返回。 Ruby使用sort_by
來實現這種類型的排序。
sort_by
不使用<=>
外部,所以你可以通過簡單地告訴它如何獲得你想要比較的值進行排序:
class Foo
attr_reader :i, :c
def initialize(i, c)
@i = i
@c = c
end
end
這裏的對象數組。請注意,他們是在創建它們的順序,但不排序:
foo.sort_by{ |f| f.i }
# => [#<Foo:0x007f97d1061d80 @c="z", @i=1>,
# #<Foo:0x007f97d1061d30 @c="x", @i=2>,
# #<Foo:0x007f97d1061ce0 @c="b", @i=25>,
# #<Foo:0x007f97d1061d58 @c="a", @i=26>]
由字符值對它們進行排序:
foo.sort_by{ |f| f.c }
# => [#<Foo:0x007f97d1061d58 @c="a", @i=26>,
# #<Foo:0x007f97d1061ce0 @c="b", @i=25>,
# #<Foo:0x007f97d1061d30 @c="x", @i=2>,
# #<Foo:0x007f97d1061d80 @c="z", @i=1>]
foo = [[1, 'z'], [26, 'a'], [2, 'x'], [25, 'b'] ].map { |i, c| Foo.new(i, c) }
# => [#<Foo:0x007f97d1061d80 @c="z", @i=1>,
# #<Foo:0x007f97d1061d58 @c="a", @i=26>,
# #<Foo:0x007f97d1061d30 @c="x", @i=2>,
# #<Foo:0x007f97d1061ce0 @c="b", @i=25>]
由整數值對它們進行排序sort_by
不響應,以及使用一個否定的值作爲sort
和<=>
,因此,基於some benchmarks做了一段時間後對堆棧溢出,我們知道,在所得到的值用reverse
是從上升到下降開關訂單的最快方法:
foo.sort_by{ |f| f.i }.reverse
# => [#<Foo:0x007f97d1061d58 @c="a", @i=26>,
# #<Foo:0x007f97d1061ce0 @c="b", @i=25>,
# #<Foo:0x007f97d1061d30 @c="x", @i=2>,
# #<Foo:0x007f97d1061d80 @c="z", @i=1>]
foo.sort_by{ |f| f.c }.reverse
# => [#<Foo:0x007f97d1061d80 @c="z", @i=1>,
# #<Foo:0x007f97d1061d30 @c="x", @i=2>,
# #<Foo:0x007f97d1061ce0 @c="b", @i=25>,
# #<Foo:0x007f97d1061d58 @c="a", @i=26>]
他們有點互換,但你要記住,sort_by
確實有開銷,這是顯而易見的,當您在對簡單對象運行時將其時間與sort
時間進行比較。在正確的時間使用正確的方法,你可以看到戲劇性的加速。
如果顛倒的項目則排序改變像降序的順序和升序 – uday
I * HOPE *爲Ruby的教程沒有建議你使用駝峯你的變量。在Ruby中,我們使用snake_case作爲變量。 –
我真的不記得 - 這只是個人喜好。我真的不喜歡在變量名中看到_。 – MrDuk