在第一位的,:
File.open(ARGV[0], "r").each_line do |line|
用途:
File.foreach(ARGV[0]) do |line|
,而不是和:
incr += 1
if incr % 3 == 0
用途:
if $. % 3 == 0
$.
是最後讀取行的行號的變量。
代替
在第二個,:
line.gsub("(","").gsub(")","").split(",").map{ |s| s.to_i}
使用:
line.tr('()', '').split(',').map(&:to_i)
在第三個,而不是:
line.split("),(").map{ |s| s.gsub("(","").gsub(")","").split(",").map{ |s| s.to_i}}
使用:
line.scan(/(?:\d+,?)+/).map{ |s| s.split(',', 0).map(&:to_i) }
下面是該行的工作原理:
line.scan(/(?:\d+,?)+/)
=> ["1,2,3,", "1,2,3,"]
line.scan(/(?:\d+,?)+/).map{ |s| s.split(',',0) }
=> [["1", "2", "3"], ["1", "2", "3"]]
line.scan(/(?:\d+,?)+/).map{ |s| s.split(',', 0).map(&:to_i) }
=> [[1, 2, 3], [1, 2, 3]]
我沒有運行任何基準測試比較速度,但變化應該會更快一點,因爲在gsub
電話都沒有了。我所做的改變並不一定是最快捷的做法,它們是您自己代碼的更優化版本。
嘗試將Ruby的速度與其他語言進行比較,需要了解基於該步驟的多個基準測試完成每個步驟的最快方法。這也意味着你在相同的硬件和操作系統上運行,並且你的語言都被編譯爲最高效的表單。語言對存儲器使用與速度進行權衡,因此,儘管可能比另一個速度慢,但它也可能更有效率。
另外,在生產環境中進行編碼時,生成正確工作的代碼的時間必須考慮到「哪個更快」的方程中。 C的速度非常快,但是對於大多數問題,編寫程序比Ruby需要更長的時間,因爲C不像Ruby那樣握住你的手。當C代碼需要一週的時間來編寫和調試時,哪一個更快,而Ruby代碼需要一個小時?只是想想。
我沒有閱讀@ tadman的回答和評論,直到我完成。使用:
map(&:to_i)
曾經是慢於:
map{ |s| s.to_i }
速度差異取決於你正在運行的Ruby版本。最初使用&:
已在一些猴子補丁中實現,但現在它已內置到Ruby中。當他們作出改變它加快了很多:
require 'benchmark'
foo = [*('1'..'1000')] * 1000
puts foo.size
N = 10
puts "N=#{N}"
puts RUBY_VERSION
puts
Benchmark.bm(6) do |x|
x.report('&:to_i') { N.times { foo.map(&:to_i) }}
x.report('to_i') { N.times { foo.map{ |s| s.to_i } }}
end
,輸出:
1000000
N=10
2.0.0
user system total real
&:to_i 1.240000 0.000000 1.240000 ( 1.250948)
to_i 1.400000 0.000000 1.400000 ( 1.410763)
現在正經歷10,000,000元,只產生了0.2 /秒的差別。在做同樣的事情的兩種方式之間沒有太大區別。如果你要處理更多的數據,那麼它很重要。對於大多數應用程序來說,這是一個有爭議的問題,因爲其他的事情會成爲瓶頸/減速,所以編寫代碼以適合您的方式,考慮到速度差異。
要顯示的Ruby版本導致差異,這裏是使用Ruby 1.8.7相同的基準測試結果:
1000000
N=10
1.8.7
user system total real
&:to_i 4.940000 0.000000 4.940000 ( 4.945604)
to_i 2.390000 0.000000 2.390000 ( 2.396693)
至於gsub
與tr
:
require 'benchmark'
foo = '()' * 500000
puts foo.size
N = 10
puts "N=#{N}"
puts RUBY_VERSION
puts
Benchmark.bm(6) do |x|
x.report('tr') { N.times { foo.tr('()', '') }}
x.report('gsub') { N.times { foo.gsub(/[()]/, '') }}
end
有了這些結果:
1000000
N=10
1.8.7
user system total real
tr 0.010000 0.000000 0.010000 ( 0.011652)
gsub 3.010000 0.000000 3.010000 ( 3.014059)
和:
1000000
N=10
2.0.0
user system total real
tr 0.020000 0.000000 0.020000 ( 0.017230)
gsub 1.900000 0.000000 1.900000 ( 1.904083)
這裏的那種差異,我們可以從改變正則表達式,這迫使以獲得所需結果所需的處理變化看:
require 'benchmark'
line = '((1,2,3),(1,2,3))'
pattern1 = /\([\d,]+\)/
pattern2 = /\(([\d,]+)\)/
pattern3 = /\((?:\d+,?)+\)/
pattern4 = /\d(?:[\d,])+/
line.scan(pattern1) # => ["(1,2,3)", "(1,2,3)"]
line.scan(pattern2) # => [["1,2,3"], ["1,2,3"]]
line.scan(pattern3) # => ["(1,2,3)", "(1,2,3)"]
line.scan(pattern4) # => ["1,2,3", "1,2,3"]
line.scan(pattern1).map{ |s| s[1..-1].split(',').map(&:to_i) } # => [[1, 2, 3], [1, 2, 3]]
line.scan(pattern2).map{ |s| s[0].split(',').map(&:to_i) } # => [[1, 2, 3], [1, 2, 3]]
line.scan(pattern3).map{ |s| s[1..-1].split(',').map(&:to_i) } # => [[1, 2, 3], [1, 2, 3]]
line.scan(pattern4).map{ |s| s.split(',').map(&:to_i) } # => [[1, 2, 3], [1, 2, 3]]
N = 1000000
Benchmark.bm(8) do |x|
x.report('pattern1') { N.times { line.scan(pattern1).map{ |s| s[1..-1].split(',').map(&:to_i) } }}
x.report('pattern2') { N.times { line.scan(pattern2).map{ |s| s[0].split(',').map(&:to_i) } }}
x.report('pattern3') { N.times { line.scan(pattern3).map{ |s| s[1..-1].split(',').map(&:to_i) } }}
x.report('pattern4') { N.times { line.scan(pattern4).map{ |s| s.split(',').map(&:to_i) } }}
end
On Ruby 2.0-p427:
user system total real
pattern1 5.610000 0.010000 5.620000 ( 5.606556)
pattern2 5.460000 0.000000 5.460000 ( 5.467228)
pattern3 5.730000 0.000000 5.730000 ( 5.731310)
pattern4 5.080000 0.010000 5.090000 ( 5.085965)
什麼是每個文件中的「類型」?它總是「類型」?它是以下行的數據類型說明符嗎? –
類型是用於我正在測試的另一個程序,它是特定的,但ruby從不讀取它,因此您可以忽略它。我把它放在那裏,所以你知道爲什麼迭代就像它一樣工作。 – HolgerS