Arrays 在向数组中添加项时,迭代嵌套哈希以创建数组
我有一个嵌套哈希,我想重新排列键/值对。下面的示例显示了指向语言散列的样式散列,然后指向它所属语言类型的散列。我想重新格式化它,使其看起来像Arrays 在向数组中添加项时,迭代嵌套哈希以创建数组,arrays,ruby,hash,Arrays,Ruby,Hash,我有一个嵌套哈希,我想重新排列键/值对。下面的示例显示了指向语言散列的样式散列,然后指向它所属语言类型的散列。我想重新格式化它,使其看起来像new\u hash示例。我理解通过在不同级别上迭代散列并创建散列来构造它,但是,我关心/困惑的部分是创建:style指向的数组,然后将正确的样式推送到它 我假设代码片段会像我期望的那样工作。我的new_hash将有一个指向另一个hash的:language键。这个散列有一个键:style,它指向一个数组,我将在其中存储与每种语言相关联的所有样式。:java
new\u hash
示例。我理解通过在不同级别上迭代散列并创建散列来构造它,但是,我关心/困惑的部分是创建:style
指向的数组,然后将正确的样式推送到它
我假设代码片段会像我期望的那样工作。我的new_hash
将有一个指向另一个hash的:language
键。这个散列有一个键:style
,它指向一个数组,我将在其中存储与每种语言相关联的所有样式。:javascript
散列在其数组中应该有两种样式,因为它在原始的散列中存在两次,但是,当运行此代码段时,数组不会同时添加这两种样式。在分配哈希的一次迭代中,:javascript
被分配了:oo
的样式,但在另一次迭代中,它被替换为:functional
。我不确定在遍历散列时初始化数组并向其中添加多个项的语法
意识到这可以通过迭代哈希两次来解决。一次初始化数组,第二次向数组中添加必要的项。尽管不确定这是否只能迭代一次哈希
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
new={}
语言。每个do |风格,编程|语言|
编程语言。每个do语言,类型|
键入.每个do |键、值|
新的[语言]={:type=>nil,:style=>[]}
结束
结束
结束
语言。每个do |风格,编程|语言|
编程语言。每个do语言,类型|
键入.每个do |键、值|
新建[语言][:类型]=值
new[language][:style]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
一旦我们给散列起了更好的名字,它就变得更容易计算了。我还利用了,所以我们不必担心重复
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
请注意,我并没有对哈希和子哈希的初始化进行硬编码,而是在循环的每一级进行了硬编码。这意味着我不必列出所有的键,它将处理新的和意外的键
通过对值使用集合,我对一点语言信息可以包含多少值不做任何假设。您可以使用(akamerge!
)的形式,并使用散列来确定合并的两个散列中存在的键的值。详见文档
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]}}
您在散列中缺少一个大括号。这是一个很好的例子,说明了为什么应该将右大括号放在自己的行上。你可以在一个循环中完成。将内部循环合并在一起,并在添加值之前初始化。您还将多次添加:style
,它需要位于type
循环之外。它之所以能工作,是因为类型中只有一个键。始终是创造性的,而且我喜欢|uo,|
看起来像块参数的方式。有点让我笑了
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
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]}}