Array#sort_by 显然是正确的方法,但这里提醒一下如何使用 Array#sort:
a.sort do |s1,s2|
t1 = (s1.is_a? Array) ? s1.first : s1
t2 = (s2.is_a? Array) ? s2.first : s2
t1 <=> t2
end.map {|e| (e.is_a? Array) ? e.join(', ') : e }
@theTinMan指出,在这里
sort
比
sort_by
慢得多,并给出了一个解释。我一直想看看
Benchmark模块的用法,所以趁机比较了这两种方法在手头问题上的效果。我使用了@Rafa的
sort_by
解决方案和我的
sort
解决方案。
为了测试,我提前构建了一个包含100个随机样本的数组(每个样本都有10,000个要排序的随机元素),因此基准测试不包括构建样本所需的时间(这并不可忽略)。其中8,000个元素是由8个小写字母组成的随机字符串。另外2,000个元素是形如
[str1,str2]
的2元组,其中
str1
和
str2
分别是由8个小写字母组成的随机字符串。我进行了其他参数的基准测试,但底线结果没有显著变化。
require 'benchmark'
def make_samples(n, m, k, s)
s.times.with_object([]) { |_, a| a << test_array(n,m,k) }
end
def test_array(n,m,k)
a = ('a'..'z').to_a
r = []
(n-m).times { r << a.sample(k).join }
m.times { r << [a.sample(k).join, a.sample(k).join] }
r.shuffle!
end
make_samples(6,2,4,4)
n = 10000
m = 2000
k = 8
s = 100
samples = make_samples(n,m,k,s)
Benchmark.bm('sort_by'.size) do |bm|
bm.report 'sort_by' do
samples.each do |s|
s.sort_by { |f| f.class == Array ? f.first : f }
end
end
bm.report 'sort' do
samples.each do |s|
s.sort do |s1,s2|
t1 = (s1.is_a? Array) ? s1.first : s1
t2 = (s2.is_a? Array) ? s2.first : s2
t1 <=> t2
end
end
end
end
user system total real
sort_by 1.360000 0.000000 1.360000 ( 1.364781)
sort 4.050000 0.010000 4.060000 ( 4.057673)
尽管从未怀疑,@theTinMan是正确的!我用不同的参数进行了几次其他运行,一直发现
sort_by
相对于
sort
具有一致的性能优势。
请注意,sort_by
的“系统”时间为零。在其他运行中,它有时会为sort
的零值。这些值始终为零或0.010000
,让我想知道那里到底发生了什么。(我在Mac上运行了这些)。
对于不熟悉Benchmark
的读者,Benchmark#bm需要一个参数,该参数等于所需表头行(user system...
)的左填充量。 bm.report
将一行标签作为参数。