当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


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。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。