我正在使用Ruby on Rails 3,並且希望改進以下代碼以更好地完成相同的操作。改進'each'語句
query = {}
params.each { |k,v| query[k.singularize] = v }
我怎麼能這樣做?
我正在使用Ruby on Rails 3,並且希望改進以下代碼以更好地完成相同的操作。改進'each'語句
query = {}
params.each { |k,v| query[k.singularize] = v }
我怎麼能這樣做?
如果你實際上發現
params.each { |k,v| query[k.singularize] = v }
時間太長,singularize
會佔用你的大部分時間。
如果大多數單詞是相同的,我會考慮memoization。
其實,如果你有一萬個參數,我會考慮一個代碼審查!
query = Hash[params.map{|k, v| [k.singularize, v]}]
嗯,我有一個想法(原理相同澤),並決定我想知道這是否是一個進步。這裏的基準測試結果:
params = {'puppies' => 'cute',
'dinosaurs' => 'angry',
'kittens' => 'kill them all',
'wat' => 4}
Benchmark.bm do |x|
x.report(".each"){10000.times{query = {}; params.each{ |k,v| query[k.singularize] = v }}}
x.report("Hash"){10000.times{query = Hash[params.map{|k, v| [k.singularize, v]}]}}
end
而結果:
user system total real
.each 3.850000 0.390000 4.240000 ( 4.260567)
Hash 3.910000 0.400000 4.310000 ( 4.402304)
所以差別非常小,雖然哈希是改善相反,遺憾的是 - 如果性能是你所關心。
我仍然傾向於使用Hash[]
格式,只是因爲我喜歡.map
的工作原理......但是.map
也必須遍歷每一個項目,所以它沒有什麼不同。
編輯:
我去評論建議做一個真正的大的哈希,而不是一個小散10,000次。這裏的結果:
myhash = {}
20000.times do |i|
myhash[i.to_s * 2 + 's'] = i
end
Benchmark.bm do |x|
x.report(".each"){query = {}; myhash.each{|k,v| query[k.singularize] = v}}
x.report("Hash"){query = Hash[myhash.map{|k,v| [k.singularize, v]}]}
end
結果:
user system total real
.each 1.980000 0.110000 2.090000 ( 2.100811)
Hash 2.040000 0.140000 2.180000 ( 2.176588)
編輯2:幸得澤的第三種方法:
Benchmark.bm do |x|
x.report(".each"){query = {}; myhash.each{|k,v| query[k.singularize] = v}}
x.report("Hash"){query = Hash[myhash.map{|k,v| [k.singularize, v]}]}
x.report("with_object"){query = myhash.each_with_object({}){|(k, v), h| h[k.singularize] = v}}
end
user system total real
.each 2.050000 0.110000 2.160000 ( 2.174315)
Hash 2.070000 0.110000 2.180000 ( 2.187600)
with_object 2.100000 0.110000 2.210000 ( 2.207763)
如果您(或其他人)能找到一種方法,修改每個值就地我懷疑這將是最快的方式來做到這一點:
params.each{|arr| arr[0].singularize!}
但你不能這樣做,因爲
singularize!
沒有定義,並params.each{|arr| arr[0].gsub!('s', '')}
你得到一個錯誤:
TypeError: can't modify frozen string
我只是堅持原來的版本:p
而不是做一個小哈希一萬次,嘗試做一個大哈希一次? – 2011-03-11 05:51:29
你是什麼意思,「它必須循環每個項目」?你不需要這樣做嗎? – 2011-03-11 06:10:16
@Mladen它似乎是如此。我們試圖找到一種改進的方法,我找不到一個:)所以我對這個問題的答案是「堅持原始版本」 – nzifnab 2011-03-11 06:17:45
正如nzifnab寫道,我的其他代碼似乎是緩慢的。下面的一個可能比原始發佈稍快。
query = params.each_with_object({}){|(k, v), h| h[k.singularize] = v}
我從來不知道這種方法......事實證明,你可以在stackoverflow上學習東西;)哈哈。它在語法上很酷,但在邏輯上與他原來所做的相同......我將更新我的基準。 – nzifnab 2011-03-11 06:05:56
我在Ruby YARV 1.9中試過以下內容。1,無的ActiveSupport(因此reverse
而不是singularize
)
require "benchmark"
myhash = {}
2000000.times do |i|
myhash[i.to_s * 2 + 's'] = i
end
Benchmark.bm do |x|
x.report(".each"){query = {}; myhash.each{|k,v| query[k.reverse] = v}}
x.report("Hash"){query = Hash[myhash.map{|k,v| [k.reverse, v]}]}
puts RUBY_VERSION
puts RUBY_ENGINE if defined?(RUBY_ENGINE)
end
給我
user system total real
.each 6.350000 0.070000 6.420000 ( 6.415588)
Hash 5.710000 0.100000 5.810000 ( 5.795611)
1.9.1
ruby
所以在我的情況下,哈希也較快。
考慮到我的基準和nzifnab之間的速度差異,我想檢查大部分時間不是花在singularize
上。
更新:
在1.8.7:
user system total real
.each 11.640000 0.380000 12.020000 (12.019372)
Hash 15.010000 0.540000 15.550000 (15.552186)
1.8.7
因此,它是慢1.8下使用Hash?
我正在使用Ruby 1.8.7 - 我的基準測試版具有大約相同速度的兩個版本(使用'.reverse') - 我想知道使用散列路由的更新版本還是Ruby更快。 – nzifnab 2011-03-11 06:36:39
它仍然循環數據一次並複製值。我也打算髮布這個確切的代碼,但我不認爲這是一個改進。如果有什麼更難閱讀。要在兩者之間運行一個基準,以查看性能是否有差異。待定... – nzifnab 2011-03-11 05:30:44
您的代碼無效。 – 2011-03-11 05:30:44
呃他錯過了最後一個關閉支架,沒有biggie – nzifnab 2011-03-11 05:31:22