當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Ruby Enumerable.sort_by用法及代碼示例


本文簡要介紹ruby語言中 Enumerable.sort_by 的用法。

用法

sort_by {|element| ... } → array
sort_by → enumerator

給定一個塊,返回一個元素數組 self ,根據塊為每個元素返回的值排序。相等元素的順序是不確定的並且可能是不穩定的。

例子:

a = %w[xx xxx x xxxx]
a.sort_by {|s| s.size }        # => ["x", "xx", "xxx", "xxxx"]
a.sort_by {|s| -s.size }       # => ["xxxx", "xxx", "xx", "x"]
h = {foo: 2, bar: 1, baz: 0}
h.sort_by{|key, value| value } # => [[:baz, 0], [:bar, 1], [:foo, 2]]
h.sort_by{|key, value| key }   # => [[:bar, 1], [:baz, 0], [:foo, 2]]

如果沒有給出塊,則返回 Enumerator

sort_by 的當前實現生成一個包含原始集合元素和映射值的元組數組。這使得 sort_by 在鍵集很簡單時相當昂貴。

require 'benchmark'

a = (1..100000).map { rand(100000) }

Benchmark.bm(10) do |b|
  b.report("Sort")    { a.sort }
  b.report("Sort by") { a.sort_by { |a| a } }
end

產生:

user     system      total        real
Sort        0.180000   0.000000   0.180000 (  0.175469)
Sort by     1.980000   0.040000   2.020000 (  2.013586)

但是,請考慮比較 key 是一項重要操作的情況。以下代碼使用基本的 sort 方法對修改時間的一些文件進行排序。

files = Dir["*"]
sorted = files.sort { |a, b| File.new(a).mtime <=> File.new(b).mtime }
sorted   #=> ["mon", "tues", "wed", "thurs"]

這種排序效率低下:它在每次比較期間生成兩個新的 File 對象。更好的技術是使用 Kernel#test 方法直接生成修改時間。

files = Dir["*"]
sorted = files.sort { |a, b|
  test(?M, a) <=> test(?M, b)
}
sorted   #=> ["mon", "tues", "wed", "thurs"]

這仍然會生成許多不必要的 Time 對象。一種更有效的技術是在排序之前緩存排序鍵(在這種情況下是修改時間)。 Perl 用戶經常將這種方法稱為 Schwartzian 變換,以 Randal Schwartz 命名。我們構建了一個臨時數組,其中每個元素都是一個包含排序鍵和文件名的數組。我們對這個數組進行排序,然後從結果中提取文件名。

sorted = Dir["*"].collect { |f|
   [test(?M, f), f]
}.sort.collect { |f| f[1] }
sorted   #=> ["mon", "tues", "wed", "thurs"]

這正是 sort_by 在內部所做的。

sorted = Dir["*"].sort_by { |f| test(?M, f) }
sorted   #=> ["mon", "tues", "wed", "thurs"]

要產生特定順序的反向,可以使用以下命令:

ary.sort_by { ... }.reverse!

相關用法


注:本文由純淨天空篩選整理自ruby-lang.org大神的英文原創作品 Enumerable.sort_by。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。