开发者

Ruby: Is there a more efficient way to convert a subset of hash keys to underscored symbols?

开发者 https://www.devze.com 2023-03-24 20:06 出处:网络
I a开发者_开发百科m looking to go from this {\'productId\' => \'1234\', \'unwantedKey\' => \'nope\'}

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
0

精彩评论

暂无评论...
验证码 换一张
取 消