Ruby:将嵌套的 Ruby 哈希转换为非嵌套的哈希

标签 ruby hash nested-attributes

现在,我有一个服务器调用会返回以下 Ruby 哈希:

{
  "id"=>"-ct",
  "factualId"=>"",
  "outOfBusiness"=>false,
  "publishedAt"=>"2012-03-09 11:02:01",
  "general"=>{
    "name"=>"A Cote",
    "timeZone"=>"EST",
    "desc"=>"À Côté is a small-plates restaurant in Oakland's charming
            Rockridge district. Cozy tables surround large communal tables in both
            the main dining room and on the sunny patio to create a festive atmosphere.
              Small plates reflecting the best of seasonal Mediterranean cuisine are served
            family-style by a friendly and knowledgeable staff.\nMenu items are paired with
            a carefully chosen selection of over 40 wines by the glass as well as a highly
            diverse bottled wine menu. Specialty drinks featuring fresh fruits, rare
            botaniques and fine liqueurs are featured at the bar.",
    "website"=>"http://acoterestaurant.com/"
  },
  "location"=>{
    "address1"=>"5478 College Ave",
    "address2"=>"",
    "city"=>"Oakland",
    "region"=>"CA",
    "country"=>"US",
    "postcode"=>"94618",
    "longitude"=>37.84235,
    "latitude"=>-122.25222
  },
  "phones"=>{
    "main"=>"510-655-6469",
    "fax"=>nil
  },
  "hours"=>{
    "mon"=>{"start"=>"", "end"=>""},
    "tue"=>{"start"=>"", "end"=>""},
    "wed"=>{"start"=>"", "end"=>""},
    "thu"=>{"start"=>"", "end"=>""},
    "fri"=>{"start"=>"", "end"=>""},
    "sat"=>{"start"=>"", "end"=>""},
    "sun"=>{"start"=>"", "end"=>""},
    "holidaySchedule"=>""
  },
  "businessType"=>"Restaurant"
}

它有几个嵌套的属性,例如:

"wed"=>{"start"=>"", "end"=>""}

我需要将此对象转换为 Ruby 中的未嵌套哈希。理想情况下,我想检测一个属性是否嵌套,并相应地做出响应,I.E.当它确定属性“wed”时' 是嵌套的,它会提取数据并存储在字段 ' wed-start 中' 和 ' wed-end ',或类似的东西。

有人对如何开始有任何建议吗?

最佳答案

编辑:sparsify gem作为此问题的通用解决方案发布。


这是我几个月前完成的一个实现。您需要将 JSON 解析为散列,然后使用 Sparsify 来稀疏散列。

# Extend into a hash to provide sparse and unsparse methods. 
# 
# {'foo'=>{'bar'=>'bingo'}}.sparse #=> {'foo.bar'=>'bingo'}
# {'foo.bar'=>'bingo'}.unsparse => {'foo'=>{'bar'=>'bingo'}}
# 
module Sparsify
  def sparse(options={})
    self.map do |k,v|
      prefix = (options.fetch(:prefix,[])+[k])
      next Sparsify::sparse( v, options.merge(:prefix => prefix ) ) if v.is_a? Hash
      { prefix.join(options.fetch( :separator, '.') ) => v}
    end.reduce(:merge) || Hash.new
  end
  def sparse!
    self.replace(sparse)
  end

  def unsparse(options={})
    ret = Hash.new
    sparse.each do |k,v|
      current = ret
      key = k.to_s.split( options.fetch( :separator, '.') )
      current = (current[key.shift] ||= Hash.new) until (key.size<=1)
      current[key.first] = v
    end
    return ret
  end
  def unsparse!(options={})
    self.replace(unsparse)
  end

  def self.sparse(hsh,options={})
    hsh.dup.extend(self).sparse(options)
  end

  def self.unsparse(hsh,options={})
    hsh.dup.extend(self).unsparse(options)
  end

  def self.extended(base)
    raise ArgumentError, "<#{base.inspect}> must be a Hash" unless base.is_a? Hash
  end
end

用法:

external_data = JSON.decode( external_json )
flattened = Sparsify.sparse( external_data, :separator => '-' )

这最初是因为我们在 Mongo 中存储一组东西而创建的,这允许我们在更新时使用稀疏键(点分隔)来更新嵌套哈希的一些内容,而不会覆盖不相关的键。

关于Ruby:将嵌套的 Ruby 哈希转换为非嵌套的哈希,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12064648/

相关文章:

database - 关于哈希盐的综合信息

Javascript 哈希短字符串的异常行为

c - 计算 C Union 的哈希码的有效方法是什么?

ruby-on-rails-4 - Rails 4 - 带有 accepts_nested_attributes_for Controller 设置的嵌套表单?

ruby-on-rails - 在 Mac 上安装 Postgres gem 时出错

ruby - 使用嵌套散列和散列作为默认值未按预期工作

ruby-on-rails - has_many 嵌套表单,其中包含 has_one 嵌套表单

ruby-on-rails - Ruby on Rails 回形针多重上传与嵌套属性

ruby - 故意在 Ruby 1.8.7 下造成段错误

ruby - 排序嵌套哈希错误 "can' t 将符号转换为整数”