当速度可能成为问题并且 sort 密钥的计算成本很高时,总是更喜欢 sort_by 而不是 sort。
对于升序,只需按原样使用排序键,此处为a(数组元素的值)。对于降序,使用-key(减键),这里是-a.to_s.length(数组元素的长度):
array = [20, 10, 40, 1200, 300]
puts array.sort_by { |a| [-a.to_s.length, a] }
打印:
1200
300
10
20
40
哪个更快:sort_by 或 sort?
sort_by [is] 当键集很简单时相当昂贵。 ...
但是,考虑比较密钥是不平凡的情况
手术。一种更有效的技术是缓存sort 键...
在sort 之前。 Perl 用户通常称这种方法为 Schwartzian
在 Randal Schwartz 之后转变。 ...这正是sort_by
在内部进行。
(来自sort_by docs)
另见
Brandon Dimcheff: "Ruby's sort vs. sort_by"
基准测试sort_by 与sort:
对于 OP 描述的情况,sort_by 比sort 稍快,尽管两者都很快,因为数组很小(size = 5,见下文)。随着数组增长到更真实的size=10, 100, 1000,sort_by 的速度大约是原来的两倍,因为减少了对昂贵的sort 键计算的需求。请注意,相对性能在很大程度上取决于数组大小以及计算 sort 键的成本,因此将其视为单个数据点,不要过度概括这些结果。
代码:
#!/usr/bin/env ruby
require 'benchmark'
max_val = 2_000
[5, 10, 100, 1000].each do |size|
puts "###"
puts "array size=#{size}:"
puts "###"
Benchmark.bmbm do |x|
Kernel.srand(1234)
x.report("sort_by") { 10000.times { (1..size).to_a.map { rand(max_val) } .sort_by { |a| [-a.to_s.length, a] } } }
Kernel.srand(1234)
x.report("sort") { 10000.times { (1..size).to_a.map { rand(max_val) } .sort { |a, b| [b.to_s.length, a] <=> [a.to_s.length, b] } } }
end
end
结果:
###
array size=5:
###
Rehearsal -------------------------------------------
sort_by 0.070000 0.000000 0.070000 ( 0.062603)
sort 0.070000 0.000000 0.070000 ( 0.074214)
---------------------------------- total: 0.140000sec
user system total real
sort_by 0.060000 0.000000 0.060000 ( 0.061337)
sort 0.070000 0.000000 0.070000 ( 0.070706)
###
array size=10:
###
Rehearsal -------------------------------------------
sort_by 0.110000 0.000000 0.110000 ( 0.117958)
sort 0.190000 0.000000 0.190000 ( 0.183992)
---------------------------------- total: 0.300000sec
user system total real
sort_by 0.110000 0.000000 0.110000 ( 0.116410)
sort 0.180000 0.000000 0.180000 ( 0.184045)
###
array size=100:
###
Rehearsal -------------------------------------------
sort_by 1.770000 0.010000 1.780000 ( 1.776254)
sort 3.800000 0.000000 3.800000 ( 3.797437)
---------------------------------- total: 5.580000sec
user system total real
sort_by 1.780000 0.000000 1.780000 ( 1.783407)
sort 3.860000 0.000000 3.860000 ( 3.865884)
###
array size=1000:
###
Rehearsal -------------------------------------------
sort_by 25.380000 0.010000 25.390000 ( 25.403899)
sort 60.290000 0.040000 60.330000 ( 60.374564)
--------------------------------- total: 85.720000sec
user system total real
sort_by 26.010000 0.060000 26.070000 ( 26.122175)
sort 60.990000 0.060000 61.050000 ( 61.134355)