概要
ハッシュが与えられた場合、使用するキーのリストに基づいてサブセットハッシュを作成する最も効率的な方法は何ですか?
h1 = { a:1, b:2, c:3 } # Given a hash...
p foo( h1, :a, :c, :d ) # ...create a method that...
#=> { :a=>1, :c=>3, :d=>nil } # ...returns specified keys...
#=> { :a=>1, :c=>3 } # ...or perhaps only keys that exist
詳細
Sequelデータベースツールキットを使用すると、ハッシュを渡すことでモデルインスタンスを作成または更新できます。
foo = Product.create( hash_of_column_values )
foo.update( another_hash )
Sinatra Webフレームワークは、params
フォーム変数、クエリ文字列パラメーター、およびルート一致を含む名前付きハッシュを利用できるようにします。
データベース列と同じ名前のフィールドのみを保持するフォームを作成し、それをこのルートに投稿すると、すべてが非常に便利に機能します。
post "/create_product" do
new_product = Product.create params
redirect "/product/#{new_product.id}"
end
ただし、これは壊れやすく危険です。悪意のあるハッカーが、変更を意図していない列を含むフォームを投稿して更新する可能性があるため、危険です。このルートで同じフォームを使用すると機能しないため、壊れやすいです。
post "/update_product/:foo" do |prod_id|
if product = Product[prod_id]
product.update(params)
#=> <Sequel::Error: method foo= doesn't exist or access is restricted to it>
end
end
したがって、堅牢性とセキュリティのために、これを記述できるようにしたいと思います。
post "/update_product/:foo" do |prod_id|
if product = Product[prod_id]
# Only update two specific fields
product.update(params.slice(:name,:description))
# The above assumes a Hash (or Sinatra params) monkeypatch
# I will also accept standalone helper methods that perform the same
end
end
...より冗長で非DRYオプションの代わりに:
post "/update_product/:foo" do |prod_id|
if product = Product[prod_id]
# Only update two specific fields
product.update({
name:params[:name],
description:params[:description]
})
end
end
更新:ベンチマーク
(現在の)実装のベンチマークの結果は次のとおりです。
user system total real
sawa2 0.250000 0.000000 0.250000 ( 0.269027)
phrogz2 0.280000 0.000000 0.280000 ( 0.275027)
sawa1 0.297000 0.000000 0.297000 ( 0.293029)
phrogz3 0.296000 0.000000 0.296000 ( 0.307031)
phrogz1 0.328000 0.000000 0.328000 ( 0.319032)
activesupport 0.639000 0.000000 0.639000 ( 0.657066)
mladen 1.716000 0.000000 1.716000 ( 1.725172)
@sawaによる2番目の回答は、すべての中で最速であり、私のtap
ベースの実装の前にあります(彼の最初の回答に基づく)。チェックを追加することを選択すると、has_key?
時間がほとんど追加されず、ActiveSupportの2倍以上の速度が得られます。
ベンチマークコードは次のとおりです。
h1 = Hash[ ('a'..'z').zip(1..26) ]
keys = %w[a z c d g A x]
n = 60000
require 'benchmark'
Benchmark.bmbm do |x|
%w[ sawa2 phrogz2 sawa1 phrogz3 phrogz1 activesupport mladen ].each do |m|
x.report(m){ n.times{ h1.send(m,*keys) } }
end
end