Ruby: Is there a more efficient way to convert a subset of hash keys to underscored symbols?
I a开发者_开发百科m looking to go from this
{'productId' => '1234', 'unwantedKey' => 'nope'}
to
{:product_id => '1234'}
assuming in this example I only want the productId key/value. In the code below, api_key
returns an array of keys I'd like to extract from the hash. Is there a better approach?
product.delete_if { |k, v| !api_keys.include? k }.inject({}){|memo,(k,v)| memo[k.underscore.to_sym] = v; memo}
You could filter the api_keys
and then use each_with_object
to build your hash slice:
slice = api_keys.find_all { |k| h.has_key?(k) }.each_with_object({ }) { |k,o| o[k.underscore.to_sym] = h[k] }
each_with_object
is usually a better choice than inject
if you're iterating rather than reducing.
Given:
h = { 'productId' => '1234', 'unwantedKey' => 'nope' }
api_keys = [ 'productId' ]
The above yeilds:
slice = { :product_id => '1234' }
The find_all
/each_with_object
also has the added advantage of being explicitly driven by api_keys
(i.e. the keys you want) and that may (or may not) matter to you and the people maintaining your code.
A simple solution would be doing the each and adding in another hash at the same time:
result = {}
product = {'productId' => '1234', 'unwantedKey' => 'nope'}
product.each do |key,value|
if api_keys.include?(k)
result[key.underscore.to_sym] = value
end
end
api_keys = ['productId'] # etc...
product = {'productId' => '1234', 'unwantedKey' => 'nope'}
result = product.inject({}) do |hash, (key, value)|
hash[key.underscore.to_sym] = value if api_keys.include?(key); hash
end
One thing you could think about would be whether or not you'd like to avoid the delete pass.
final = {}
initial.each do |k, v|
final[k.underscore.sym] = v if api_keys.include?(k)
end
or
final = initial.inject({}) do |h, (k,v)|
h[k.underscore.sym] = v if api_keys.include?(k)
h
end
This question is old but since I stumbled upon it, others might too. Here's my take, assuming ActiveSupport core extensions are loaded since you're using String#underscore
:
hash = {'productId' => '1234', 'unwantedKey' => 'nope'}
api_keys = ['productId']
filtered = hash.slice(*api_keys).each.with_object({}) do |(k,v),h|
h[k.underscore.to_sym] = v
end
精彩评论