ruby - 如何在 Ruby 中使用键进行深度转换值?

标签 ruby hash activesupport

Active Support 的 deep_transform_values 递归地转换哈希的所有值。但是,是否有类似的方法可以在转换时访问值的键?

我希望能够执行以下操作:

keys_not_to_transform = ['id', 'count']

response = { result: 'ok', errors: [], data: { id: '123', price: '100.0', quotes: ['1.0', '2.0'] }, count: 10 }
response.deep_transform_values! do |key, value|
  # Use value's key to help decide what to do
  return value if keys_not_to_transform.any? key.to_s

  s = value.to_s
  if s.present? && /\A[+-]?\d+(\.\d+)?\z/.match?(s)
    return BigDecimal(s)
  else
    value
  end
end

#Expected result 
# =>{:result=>"ok", :errors=>[], :data=>{:id=>"123", :price=>0.1e3, :quotes=>[0.1e1, 0.2e1]}, :count=>10}

请注意,我们对转换 key 本身不感兴趣,只是在转换相应值时手头有它。

最佳答案

您可以使用Hash#deep_merge! (由 ActiveSupport 提供)如下:

keys_not_to_transform = ['id', 'count']

transform_value = lambda do |value|
    s = value.to_s
    if s.present? && /\A[+-]?\d+(\.\d+)?\z/.match?(s)
      BigDecimal(s)
    else
      value
    end
end

transform = Proc.new do |key,value|
  if keys_not_to_transform.include? key.to_s
    value
  elsif value.is_a?(Array)
    value.map! do |v| 
      v.is_a?(Hash) ? v.deep_merge!(v,&transform) : transform_value.(v)
    end 
  else   
    transform_value.(value)
  end  
end

response = { result: 'ok', errors: [], data: { id: '123', price: '100.0', quotes: ['1.0', '2.0'], other: [{id: '124', price: '17.0'}] }, count: 10 }

response.deep_merge!(response, &transform)

输出:

#=>{:result=>"ok", :errors=>[], :data=>{:id=>"123", :price=>0.1e3, :quotes=>[0.1e1, 0.2e1], :other=>[{:id=>"124", :price=>0.17e2}]}, :count=>10}

关于ruby - 如何在 Ruby 中使用键进行深度转换值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59375477/

相关文章:

ruby - 如何在 Windows 上使用 Thin 启动和停止 Sinatra 应用程序?

ruby - Ruby 中 nil 的定义在哪里

ruby-on-rails - 使用 Sunspot 从 Solr 索引中排除文章草稿

ruby - 在每个值都是数组的哈希中,如何使用数组项查找键?

Ruby:如何按年查找日期

ruby - 更改 Date 对象的月份而不返回新日期

ruby-on-rails - 未设置正则表达式全局变量

Ruby 使用 Nokogiri 解析 HTTPresponse

java - Go SHA-256 哈希不同于 Java SHA-256 哈希

python - 散列不确定的对象