我有一个嵌套的哈希,我想重新排列键/值对。下面的示例显示了指向语言哈希的样式哈希值,然后指向它所使用的语言类型的哈希值。我想将其重新格式化为new_hash
示例。我理解通过在不同级别迭代哈希并创建类似的哈希来构造它,但是,我关注/困惑的部分是创建:style
指向的数组然后推送正确的它的风格。
我认为代码段会像我期望的那样工作。我的new_hash
将有一个:language
的键,指向另一个哈希值。这个哈希有一个:style
的键,指向一个数组,我将在其中存储与每种语言相关的所有样式。 :javascript
哈希在其数组中应该有两个样式,因为它在原始hash
中存在两次,但是,在运行此代码片段时,该数组不会添加这两种样式。似乎在分配哈希时的一次迭代中,:javascript
被赋予:oo
的样式,但在另一次迭代中,它被:functional
替换。 我不确定初始化数组的语法,并在迭代哈希时为其添加多个项目。
hash = {
:oo => {
:ruby => {:type => "Interpreted"},
:javascript => {:type => "Interpreted"},
},
:functional => {
:scala => {:type => "Compiled"},
:javascript => {:type => "Interpreted"}
}
}
new_hash = {
:ruby => {
:type => "Interpreted", :style => [:oo]
},
:javascript => {
:type => "Interpreted", :style => [:oo, :functional]
},
:scala => {
:type => "Compiled", :style => [:functional]
}
}
hash.each do |style, programming_language|
programming_language.each do |language, type|
type.each do |key, value|
new_hash[language] = {:style => [style]}
end
end
end
答案 0 :(得分:2)
您可以使用Hash#update(aka merge!
)和Hash#merge的形式使用哈希来确定合并的两个哈希中存在的键的值。有关详细信息,请参阅文档。
hash.each_with_object({}) do |(style,language_to_type_hash),h|
language_to_type_hash.each do |language,type_hash|
h.update(language=> { type: type_hash[:type], style: [style] }) do |_,o,_|
o.merge(style: [style]) { |_,ostyle_arr,nstyle_arr| ostyle_arr + nstyle_arr }
end
end
end
#=> {:ruby =>{:type=>"Interpreted", :style=>[:oo]},
# :javascript=>{:type=>"Interpreted", :style=>[:oo, :functional]},
# :scala =>{:type=>"Compiled", :style=>[:functional]}}
答案 1 :(得分:1)
Hash::new
允许您为不存在的键指定默认值,因此在您的情况下,默认值为{type: nil, style: []}
此功能允许您只循环一次并按如下方式实现
programming_languages = {
:oo => {
:ruby => {:type => "Interpreted"},
:javascript => {:type => "Interpreted"},
},
:functional => {
:scala => {:type => "Compiled"},
:javascript => {:type => "Interpreted"}
}
}
programming_languages.each_with_object(Hash.new {|h,k| h[k] = {type: nil, style: []}}) do |(style,languages),obj|
languages.each do |language,type_hash|
obj[language][:style] << style
obj[language][:type] = type_hash[:type]
end
end
输出:
#=> {:ruby=>{:type=>"Interpreted", :style=>[:oo]},
:javascript=>{:type=>"Interpreted", :style=>[:oo, :functional]},
:scala=>{:type=>"Compiled", :style=>[:functional]}}
答案 2 :(得分:0)
意识到这可以通过迭代迭代两次来解决。一旦初始化数组,第二次再添加必要的项目。虽然不确定这是否只能迭代哈希一次。
new = {}
languages.each do |style, programming_language|
programming_language.each do |language, type|
type.each do |key, value|
new[language] = {:type => nil , :style => []}
end
end
end
languages.each do |style, programming_language|
programming_language.each do |language, type|
type.each do |key, value|
new[language][:type] = value
new[language][:style] << style
end
end
end
new
答案 3 :(得分:0)
一旦我们给哈希更好的名字,它就会变得容易一些。我也使用了sets,因此我们不必担心重复。
require 'set'
# Our new hash of language info. _new to differentiate between
# the hash of languages under the hash of styles.
languages_new = {}
# For each style...
styles.each do |style, languages|
# For each language in that style...
languages.each do |language, info|
# Add a new hash for that language if there isn't one already
languages_new[language] ||= {}
# For each bit of info about that language...
info.each do |key, val|
# Add a new set for that info if there isn't one already
# The `var = hash[key] ||= new_var` pattern allows
# conditional initialization while also using either the
# new or existing set.
set = languages_new[language][key] ||= Set.new
# Add the info to it
set.add(val)
end
# Handle the special case of style.
set = languages_new[language][:style] ||= Set.new
set.add(style)
end
end
请注意,我没有对哈希和子哈希的初始化进行硬编码,而是在每个循环级别中完成了它。这意味着我不必列出所有密钥,它将处理新的和意外的密钥。
通过对值使用集合,我不会假设一些语言信息可以有多少值。