现在,我有一台服务器调用踢回了下面的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中嵌套的哈希值。 理想情况下,我想检测是否属性被嵌套,并且作出相应的反应,即,当它确定了属性“ wed
”嵌套,它拉出它的数据,并存储在字段“ wed-start
”和“ wed-end
”,或类似的东西。
任何人对如何开始任何提示?
Answer 1:
下面是在一个完整的解决方案第一晋级。 我敢肯定,你可以更优雅写,但这似乎相当清楚。 如果你把它保存在一个Ruby文件并运行它,你会得到的输出I下面显示。
class Hash
def unnest
new_hash = {}
each do |key,val|
if val.is_a?(Hash)
new_hash.merge!(val.prefix_keys("#{key}-"))
else
new_hash[key] = val
end
end
new_hash
end
def prefix_keys(prefix)
Hash[map{|key,val| [prefix + key, val]}].unnest
end
end
p ({"a" => 2, "f" => 5}).unnest
p ({"a" => {"b" => 3}, "f" => 5}).unnest
p ({"a" => {"b" => {"c" => 4}, "f" => 5}}).unnest
输出:
{"a"=>2, "f"=>5}
{"a-b"=>3, "f"=>5}
{"a-b-c"=>4, "a-f"=>5}
Answer 2:
编辑: sparsify宝石被发布了作为一般的解决这个问题。
下面是我几个月前激动的实现。 你需要的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 => '-' )
这最初创建,因为我们与存储蒙戈一套东西,这使我们能够使用上的更新稀疏键(用点分隔)来更新嵌套哈希的部分内容,而不会覆盖按键无关的工作。
Answer 3:
还有一个选项:
class Hash
def smash(prefix = nil)
inject({}) do |acc, (k, v)|
key = prefix.to_s + k
if Hash === v
acc.merge(v.smash(key + '-'))
else
acc.merge(key => v)
end
end
end
end
hash = {
'f' => 100,
'z' => {'j' => 25},
'a' => {'b' => {'c' => 1}}
}
puts hash.smash # => {"f"=>100, "z-j"=>25, "a-b-c"=>1}
Answer 4:
解决这个另一种方式是不扁平化的哈希,但访问它,就好像它被夷为平地。 例如,假设该散列:
h = {
'a' => 1,
'b' => {
'c' => 2,
'd' => 3,
},
}
那么这个功能:
NESTED_KEY_SEPARATOR = '-'
NESTED_KEY_REGEX = /^(.*?)(?:#{NESTED_KEY_SEPARATOR}(.*))?$/
def nested_fetch(key, hash)
return hash if key.empty?
first_part_of_key, rest_of_key = NESTED_KEY_REGEX.match(key).captures
value = hash[first_part_of_key]
if value.is_a?(Hash)
nested_hash_fetch(value, rest_of_key || '')
elsif rest_of_key
nil
else
value
end
end
将让你与KEY_SEPARATOR串接各个哈希键一起检索嵌套的散列单元(套到这里冲,但可能是永远不会出现在您需要搜索哈希的关键任何字符):
p nested_fetch('a', h) # => 1
p nested_fetch('b-c', h) # => 2
如果你给一个部分限定的关键,你在那个点相匹配的哈希:
p nested_fetch('b', h) # => {"c"=>2, "d"=>3}
如果你给一个不存在的键,你会得到零:
p nested_fetch('b-x', h) # => nil
这可能是猴配接到散列,如果需要,通过简单地包封在类哈希上面的代码,并通过给自作为默认参数散列:
class Hash
NESTED_KEY_SEPARATOR = '-'
NESTED_KEY_REGEX = /^(.*?)(?:#{KEY_SEPARATOR}(.*))?$/
def nested_fetch(key, hash = self)
...
end
文章来源: Ruby: Converting a nested Ruby hash to an un-nested one