やりたいこと
文字列のタイム表示を昇順で並び替える。
条件
- 文字列の形式は
00:00.00
(分 : 秒 . 小数点以下2ケタ) - 想定のタイム範囲は
05:00.00
から10:59.99
- 件数はおよそ250件
環境
- Ruby 3.1.0p0
- macOS 10.15.7
文字列のサンプルをつくる
Integer#times
、Kernel.#rand
、Time#local
、Time#strftime
を使って250件のサンプルをつくった。
array = []
250.times { array << rand(Time.local(2022,3,14,1,5,0,0,0)..Time.local(2022,3,14,1,10,59,999) ) }
#Timeオブジェクトを`Time#strftime`を使って文字列に成形する
samples = array.map{|t| t.strftime("%M:%S.%2N")}
#=> ["10:11.12", "05:30.87", "09:59.53", "08:25.66", "07:57.37",...... "08:28.48", "07:17.87", "09:24.65", "10:47.52", "05:21.44"]
並び替えのベンチマークテストをする
[2022-03-16]修正
処理内容や数量によってsort
とsort_by
のどちらが速いかが変わるようなので、Benchmarkモジュールのbm関数を使ってテストしてみる。
試したのは次の4つ。
-
sort_by
- 文字列からintegerに変換してからsort
- 文字列のままsort
-
sort
- 文字列からintegerに変換してからsort
- 文字列のままsort
require 'benchmark'
#レポート名をつけて計測する
Benchmark.bm(10) do |x|
x.report('sort_by_i') {samples.sort_by { |s| s.delete(":.").to_i } }
x.report('sort_by_s') {samples.sort_by { |s| s } }
x.report('sort_i') {samples.sort { |a, b| a.delete(":.").to_i <=> b.delete(":.").to_i } }
x.report('sort_s') {samples.sort}
end
追記[2022-03-16]
@scivolaさんからコメントで色々と教えていただきgem.benchmark_driver
でもテストを行ってみた。
その際、
.delete(":").delete(".")
を.delete(":.")
に
samples.sort{|a,b| a <=> b}
をsamples.sort
に変更。
参考
benchmark-driver
https://github.com/benchmark-driver/benchmark-driver
まずbenchmark_driver
をインストール。
$ gem install benchmark_driver
code
require 'benchmark_driver'
#テスト対象を文字列で記入
Benchmark.driver do |x|
x.prelude <<~RUBY
array = []
250.times { array << rand(Time.local(2022,3,14,1,5,0,0,0)..Time.local(2022,3,14,1,10,59,999) ) }
samples = array.map{|t| t.strftime("%M:%S.%2N")}
RUBY
x.report 'sort_by_i' , %{ samples.sort_by \{ |s| s.delete(":.").to_i \} }
x.report 'sort_by_s' , %{ samples.sort_by \{ |s| s \} }
x.report 'sort_i' , %{ samples.sort \{ |a, b| a.delete(":.").to_i <=> b.delete(":.").to_i \} }
x.report 'sort_s' , %{ samples.sort }
end
結果
[2022-03-16]修正
benchmarkモジュールの結果
user system total real
sort_by_i 0.000199 0.000005 0.000204 ( 0.000191)
sort_by_s 0.000106 0.000000 0.000106 ( 0.000106)
sort_i 0.002053 0.000006 0.002059 ( 0.002049)
sort_s 0.000055 0.000001 0.000056 ( 0.000055)
文字列のままsort
を使うのが速いもよう。
レポートの見方はこちらの記事を参考にしました。
https://qiita.com/scivola/items/c5b2aeaf7d67a9ef310a
ちゃんと昇順に並び替えられているか確認。
p samples.sort
#=> ["05:00.13", "05:00.23", "05:00.56", "05:02.97", "05:03.29", ... "10:51.62", "10:54.19", "10:54.99", "10:55.26", "10:55.39"]
できてました。
ちなみにサンプル10件でテストした結果は以下。
#サンプル10件
user system total real
sort_by_i 0.000021 0.000004 0.000025 ( 0.000019)
sort_by_s 0.000006 0.000001 0.000007 ( 0.000006)
sort_i 0.000042 0.000001 0.000043 ( 0.000042)
sort_s 0.000003 0.000001 0.000004 ( 0.000012)
やはり文字列のままsort
を使うのが速そうです。
benchmark-driverの結果
Warming up --------------------------------------
sort_by_i 7.769k i/s - 8.426k times in 1.084521s (128.71μs/i)
sort_by_s 12.458k i/s - 13.288k times in 1.066642s (80.27μs/i)
sort_i 805.194 i/s - 810.000 times in 1.005969s (1.24ms/i)
sort_s 25.315k i/s - 26.741k times in 1.056332s (39.50μs/i)
Calculating -------------------------------------
sort_by_i 7.590k i/s - 23.307k times in 3.070740s (131.75μs/i)
sort_by_s 12.333k i/s - 37.373k times in 3.030289s (81.08μs/i)
sort_i 782.899 i/s - 2.415k times in 3.084688s (1.28ms/i)
sort_s 25.393k i/s - 75.944k times in 2.990800s (39.38μs/i)
Comparison:
sort_s: 25392.5 i/s
sort_by_s: 12333.1 i/s - 2.06x slower
sort_by_i: 7590.0 i/s - 3.35x slower
sort_i: 782.9 i/s - 32.43x slower
こちらは1秒あたりの実行回数が出るようなので、数字が大きいほうが速いということになるらしい。
文字列のままsort
する方が文字列のままsort_by
するより2倍ほど速い結果になりました。
以上