如何更新键在 ruby 中多次出现的单个哈希值?
How do I update single hash value where key appears multiple times in ruby?
我有一个嵌套的散列,我正在尝试按名称排序。
pigeon_data = {
:color => {
:purple => ["Theo", "Peter Jr.", "Lucky"],
:grey => ["Theo", "Peter Jr.", "Ms. K"],
:white => ["Queenie", "Andrew", "Ms. K", "Alex"],
:brown => ["Queenie", "Alex"]
所以我正在寻找类似
的东西
"Theo" => {
:color => ["purple", "grey"],
:gender => ["male"],
:lives => ["Subway"]
},
"Peter Jr." => {
:color => ["purple", "grey"],
:gender => ["male"],
:lives => ["Library"]
},
但每次我尝试更改其中一个值时,它最终都会更改具有相同键的所有值。
{"Theo"=>
{:color=>["purple", "grey"],
"Peter Jr."=>
{:color=>["purple", "grey"],
...
我的代码一团糟,但这里更早
代码已经将七只鸟放入嵌套哈希中作为顶级键
我认为问题出在附近
def sort_birds(new_sort_1)
new_sort_2 = Marshal.load(Marshal.dump(new_sort_1))
new_sort_1.each do |ka,va|
va.each do |kb,vb|
vb.each do |kc,vc|
#binding.pry
if vc.include?("#{ka}") && new_sort_2[ka][kb].is_a?(Array)
new_sort_2["#{ka}"][kb] << "#{kc}"
elsif vc.include?("#{ka}")
new_sort_2["#{ka}"][kb] = Array.new
new_sort_2["#{ka}"][kb] << "#{kc}"
else
鉴于提供的结构:
pigeon_data = { :color => {
:purple => ["Theo", "Peter Jr.", "Lucky"],
:grey => ["Theo", "Peter Jr.", "Ms. K"],
:white => ["Queenie", "Andrew", "Ms. K", "Alex"],
:brown => ["Queenie", "Alex"] },
:gender => {
:male => ["Alex", "Theo", "Peter Jr.", "Andrew", "Lucky"],
:female => ["Queenie", "Ms. K"] },
:lives => {
"Subway" => ["Theo", "Queenie"],
"Central Park" => ["Alex", "Ms. K", "Lucky"],
"Library" => ["Peter Jr."],
"City Hall" => ["Andrew"] } }
我们可以使用基于默认进程构建的哈希来遍历集合。
builder = Hash.new {|h,k| h[k] = Hash.new {|h2,k2| h2[k2] = []}}
pigeon_data.each_with_object(builder) do |(category,values),cage|
values.each do |cat_value,birds|
birds.each do |bird|
cage[bird][category] << cat_value
end
end
end
当构建器收到一个新键时,它会分配一个新的哈希值作为值。当这个嵌套的 Hash 收到一个新键时,它会分配一个空数组作为值。那么我们只需按照我们希望它们出现的顺序放置项目 [bird][category] << value
导致:
{"Theo"=>{
:color=>[:purple, :grey],
:gender=>[:male],
:lives=>["Subway"]},
"Peter Jr."=>{
:color=>[:purple, :grey],
:gender=>[:male],
:lives=>["Library"]},
"Lucky"=>{
:color=>[:purple],
:gender=>[:male],
:lives=>["Central Park"]},
"Ms. K"=>{
:color=>[:grey, :white],
:gender=>[:female],
:lives=>["Central Park"]},
"Queenie"=>{
:color=>[:white, :brown],
:gender=>[:female],
:lives=>["Subway"]},
"Andrew"=>{
:color=>[:white],
:gender=>[:male],
:lives=>["City Hall"]},
"Alex"=>{
:color=>[:white, :brown],
:gender=>[:male],
:lives=>["Central Park"]}}
您要做的是创建一个全新的结构,而不是试图将现有结构的副本拼凑成一个全新的形式。 Ruby 都是关于定义为一系列新对象的转换,而不是对同一对象的就地修改。
这可以这样说明:
def repigeonize(data)
# Create a target structure for this data that's a Hash with a default...
result = Hash.new do |h,k|
# ...inner hash that has...
h[k] = Hash.new do |ih, ik|
# ... arrays assigned by default to its keys.
ih[ik] = [ ]
end
end
# Iterate over the data starting at the top level where attributes...
data.each do |attr, set|
# ...have keys that represent values...
set.each do |value, names|
# ...and list the names of those with those properties.
names.each do |name|
result[name][attr] << value.to_s # Converted to a string.
end
end
end
# Pass the result back
result
end
在哪里工作是这样的:
pigeon_data = {
color: {
purple: ["Theo", "Peter Jr.", "Lucky"],
grey: ["Theo", "Peter Jr.", "Ms. K"],
white: ["Queenie", "Andrew", "Ms. K", "Alex"],
brown: ["Queenie", "Alex"]
},
lives: {
library: ["Peter Jr."],
cellar: ["Queenie","Alex"],
attic: ["Lucky","Ms. K"]
}
}
p repigeonize(pigeon_data)
# => {"Theo"=>{:color=>["purple", "grey"]}, "Peter Jr."=>{:color=>["purple", "grey"], :lives=>["library"]}, "Lucky"=>{:color=>["purple"], :lives=>["attic"]}, "Ms. K"=>{:color=>["grey", "white"], :lives=>["attic"]}, "Queenie"=>{:color=>["white", "brown"], :lives=>["cellar"]}, "Andrew"=>{:color=>["white"]}, "Alex"=>{:color=>["white", "brown"], :lives=>["cellar"]}}
{ color: pigeon_data[:color].flat_map { |k,v| [k].product(v) }.
each_with_object({}) { |(color,bird),h| (h[bird] ||= []) << color.to_s } }
#=> {:color=>{"Theo"=>["purple", "grey"],
# "Peter Jr."=>["purple", "grey"],
# "Lucky"=>["purple"],
# "Ms. K"=>["grey, "white"],
# "Queenie"=>["white, "brown"],
# "Andrew"=>["white"],
# "Alex"=>["white", "brown"]}}
步骤如下:
a = pigeon_data[:color].flat_map { |k,v| [k].product(v) }
#=> [[:purple, "Theo"], [:purple, "Peter Jr."], [:purple, "Lucky"],
# [:grey, "Theo"], [:grey, "Peter Jr."], [:grey, "Ms. K"],
# [:white, "Queenie"], [:white, "Andrew"], [:white, "Ms. K"],
# [:white, "Alex"], [:brown, "Queenie"], [:brown, "Alex"]]
b = a.each_with_object({}) { |(color,bird),h| (h[bird] ||= []) << color.to_s }
#=> {"Theo"=>["purple", "grey"], "Peter Jr."=>["purple", "grey"],
# "Lucky"=>["purple"], "Ms. K"=>["grey", "white"], "Queenie"=>["white", "brown"],
# "Andrew"=>["white"], "Alex"=>["white", "brown"]}
{ color: b }
#=> <as above>
也可以将 each_with_object({})
替换为 each_with_object(Hash.new { |h,k| h[k] = [] })
,将 (h[bird] ||= [])
替换为 h[bird]
。
参见 Enumerable#flat_map and Array#product。
我有一个嵌套的散列,我正在尝试按名称排序。
pigeon_data = {
:color => {
:purple => ["Theo", "Peter Jr.", "Lucky"],
:grey => ["Theo", "Peter Jr.", "Ms. K"],
:white => ["Queenie", "Andrew", "Ms. K", "Alex"],
:brown => ["Queenie", "Alex"]
所以我正在寻找类似
的东西 "Theo" => {
:color => ["purple", "grey"],
:gender => ["male"],
:lives => ["Subway"]
},
"Peter Jr." => {
:color => ["purple", "grey"],
:gender => ["male"],
:lives => ["Library"]
},
但每次我尝试更改其中一个值时,它最终都会更改具有相同键的所有值。
{"Theo"=>
{:color=>["purple", "grey"],
"Peter Jr."=>
{:color=>["purple", "grey"],
...
我的代码一团糟,但这里更早 代码已经将七只鸟放入嵌套哈希中作为顶级键 我认为问题出在附近
def sort_birds(new_sort_1)
new_sort_2 = Marshal.load(Marshal.dump(new_sort_1))
new_sort_1.each do |ka,va|
va.each do |kb,vb|
vb.each do |kc,vc|
#binding.pry
if vc.include?("#{ka}") && new_sort_2[ka][kb].is_a?(Array)
new_sort_2["#{ka}"][kb] << "#{kc}"
elsif vc.include?("#{ka}")
new_sort_2["#{ka}"][kb] = Array.new
new_sort_2["#{ka}"][kb] << "#{kc}"
else
鉴于提供的结构:
pigeon_data = { :color => {
:purple => ["Theo", "Peter Jr.", "Lucky"],
:grey => ["Theo", "Peter Jr.", "Ms. K"],
:white => ["Queenie", "Andrew", "Ms. K", "Alex"],
:brown => ["Queenie", "Alex"] },
:gender => {
:male => ["Alex", "Theo", "Peter Jr.", "Andrew", "Lucky"],
:female => ["Queenie", "Ms. K"] },
:lives => {
"Subway" => ["Theo", "Queenie"],
"Central Park" => ["Alex", "Ms. K", "Lucky"],
"Library" => ["Peter Jr."],
"City Hall" => ["Andrew"] } }
我们可以使用基于默认进程构建的哈希来遍历集合。
builder = Hash.new {|h,k| h[k] = Hash.new {|h2,k2| h2[k2] = []}}
pigeon_data.each_with_object(builder) do |(category,values),cage|
values.each do |cat_value,birds|
birds.each do |bird|
cage[bird][category] << cat_value
end
end
end
当构建器收到一个新键时,它会分配一个新的哈希值作为值。当这个嵌套的 Hash 收到一个新键时,它会分配一个空数组作为值。那么我们只需按照我们希望它们出现的顺序放置项目 [bird][category] << value
导致:
{"Theo"=>{
:color=>[:purple, :grey],
:gender=>[:male],
:lives=>["Subway"]},
"Peter Jr."=>{
:color=>[:purple, :grey],
:gender=>[:male],
:lives=>["Library"]},
"Lucky"=>{
:color=>[:purple],
:gender=>[:male],
:lives=>["Central Park"]},
"Ms. K"=>{
:color=>[:grey, :white],
:gender=>[:female],
:lives=>["Central Park"]},
"Queenie"=>{
:color=>[:white, :brown],
:gender=>[:female],
:lives=>["Subway"]},
"Andrew"=>{
:color=>[:white],
:gender=>[:male],
:lives=>["City Hall"]},
"Alex"=>{
:color=>[:white, :brown],
:gender=>[:male],
:lives=>["Central Park"]}}
您要做的是创建一个全新的结构,而不是试图将现有结构的副本拼凑成一个全新的形式。 Ruby 都是关于定义为一系列新对象的转换,而不是对同一对象的就地修改。
这可以这样说明:
def repigeonize(data)
# Create a target structure for this data that's a Hash with a default...
result = Hash.new do |h,k|
# ...inner hash that has...
h[k] = Hash.new do |ih, ik|
# ... arrays assigned by default to its keys.
ih[ik] = [ ]
end
end
# Iterate over the data starting at the top level where attributes...
data.each do |attr, set|
# ...have keys that represent values...
set.each do |value, names|
# ...and list the names of those with those properties.
names.each do |name|
result[name][attr] << value.to_s # Converted to a string.
end
end
end
# Pass the result back
result
end
在哪里工作是这样的:
pigeon_data = {
color: {
purple: ["Theo", "Peter Jr.", "Lucky"],
grey: ["Theo", "Peter Jr.", "Ms. K"],
white: ["Queenie", "Andrew", "Ms. K", "Alex"],
brown: ["Queenie", "Alex"]
},
lives: {
library: ["Peter Jr."],
cellar: ["Queenie","Alex"],
attic: ["Lucky","Ms. K"]
}
}
p repigeonize(pigeon_data)
# => {"Theo"=>{:color=>["purple", "grey"]}, "Peter Jr."=>{:color=>["purple", "grey"], :lives=>["library"]}, "Lucky"=>{:color=>["purple"], :lives=>["attic"]}, "Ms. K"=>{:color=>["grey", "white"], :lives=>["attic"]}, "Queenie"=>{:color=>["white", "brown"], :lives=>["cellar"]}, "Andrew"=>{:color=>["white"]}, "Alex"=>{:color=>["white", "brown"], :lives=>["cellar"]}}
{ color: pigeon_data[:color].flat_map { |k,v| [k].product(v) }.
each_with_object({}) { |(color,bird),h| (h[bird] ||= []) << color.to_s } }
#=> {:color=>{"Theo"=>["purple", "grey"],
# "Peter Jr."=>["purple", "grey"],
# "Lucky"=>["purple"],
# "Ms. K"=>["grey, "white"],
# "Queenie"=>["white, "brown"],
# "Andrew"=>["white"],
# "Alex"=>["white", "brown"]}}
步骤如下:
a = pigeon_data[:color].flat_map { |k,v| [k].product(v) }
#=> [[:purple, "Theo"], [:purple, "Peter Jr."], [:purple, "Lucky"],
# [:grey, "Theo"], [:grey, "Peter Jr."], [:grey, "Ms. K"],
# [:white, "Queenie"], [:white, "Andrew"], [:white, "Ms. K"],
# [:white, "Alex"], [:brown, "Queenie"], [:brown, "Alex"]]
b = a.each_with_object({}) { |(color,bird),h| (h[bird] ||= []) << color.to_s }
#=> {"Theo"=>["purple", "grey"], "Peter Jr."=>["purple", "grey"],
# "Lucky"=>["purple"], "Ms. K"=>["grey", "white"], "Queenie"=>["white", "brown"],
# "Andrew"=>["white"], "Alex"=>["white", "brown"]}
{ color: b }
#=> <as above>
也可以将 each_with_object({})
替换为 each_with_object(Hash.new { |h,k| h[k] = [] })
,将 (h[bird] ||= [])
替换为 h[bird]
。
参见 Enumerable#flat_map and Array#product。