为什么我的散列中只有一个值被更改?
Why is only one value in my hash being changed?
我正在制作一个简单的角色扮演游戏作为学习项目,但我对部分角色创建器有疑问。
此代码应确定分配给 player[:caste][:skill]
和 player[:sub][:skill]
的技能字符串,然后将 player[:skills]
中的每个技能值增加 2。无论什么字符串,此代码都应该有效赋值给player[:caste][:skill]
和player[:sub][:skill]
,只要等于player[:skills].to_s
即可。
目前,它只将更改应用到 player[:skills][:endurance]
而不是 player[:skills][:athletics]
。
player = {
caste: {skill: "athletics"},
sub: {skill: "endurance"},
skills: {acrobatics: 0, athletics: 0, engineering: 0, endurance: 0, heal: 0, history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0, stealth: 0, streetwise: 0, thievery: 0},
}
player[:skills] = player[:skills].map do |skill, mod|
[skill, (mod += 2 if skill.to_s == player[:caste][:skill])]
[skill, (mod += 2 if skill.to_s == player[:sub][:skill])]
end.to_h
换句话说,我的代码是 returning 以下 player[:skills]
散列:
skills: {acrobatics: 0, athletics: 0, engineering: 0, endurance: 2, heal: 0, history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0, stealth: 0, streetwise: 0, thievery: 0}
但我想要 return:
skills: {acrobatics: 0, athletics: 2, engineering: 0, endurance: 2, heal: 0, history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0, stealth: 0, streetwise: 0, thievery: 0}
如果有更简单的方法,请告诉我。我还尝试了以下方法:
player[:skills] = player[:skills].map do |skill, mod|
[skill, (mod += 2 if skill.to_s == (player[:caste][:skill] || player[:sub][:skill]))]
end.to_h
仅影响 player[:caste][:skill]
中的技能。
将代码更改为如下所示:
player = {
caste: {skill: "athletics"},
sub: {skill: "endurance"},
skills: {acrobatics: 0, athletics: 0, engineering: 0, endurance: 0, heal: 0,
history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0,
stealth: 0, streetwise: 0, thievery: 0},
}
player[:skills] = player[:skills].map do |skill, mod|
[skill, (mod += 2 if [player[:caste][:skill], player[:sub][:skill]].include?
(skill.to_s))]
end.to_h
你的代码不起作用的原因是映射 return 最后一行作为当前迭代的结果,所以在 athletics
的情况下,最后一行是
[skill, (mod += 2 if skill.to_s == player[:sub][:skill])]
将是错误的,这将是 nil
这就是为什么只有 endurance
案例有效。
希望对您有所帮助。
当我 运行 你的代码时,我得到了这个结果。
{:acrobatics=>nil, :athletics=>nil, :engineering=>nil, :endurance=>2, :heal=>nil, :history=>nil, :influence=>nil, :insight=>nil, :magicka=>nil, :perception=>nil, :riding=>nil, :stealth=>nil, :streetwise=>nil, :thievery=>nil}
那是因为 map return 执行了最后一条语句。另外,你实际上只在匹配子技能时为技能设置一个值,否则设置为零。
所以在您的代码中发生的事情是,每次迭代都是 returning 以下内容,这是传递到 map 的块中最后一条语句的结果。
[:acrobatics, nil]
[:athletics, nil]
[:engineering, nil]
[:endurance, 2]
[:heal, nil]
[:history, nil]
[:influence, nil]
[:insight, nil]
[:magicka, nil]
[:perception, nil]
[:riding, nil]
[:stealth, nil]
[:streetwise, nil]
[:thievery, nil]
最终结果是一个如下所示的数组。
[[:acrobatics, nil], [:athletics, nil], [:engineering, nil], [:endurance, 2], [:heal, nil], [:history, nil], [:influence, nil], [:insight, nil], [:magicka, nil], [:perception, nil], [:riding, nil], [:stealth, nil], [:streetwise, nil], [:thievery, nil]]
最终映射到一个新的散列
{:acrobatics=>nil, :athletics=>nil, :engineering=>nil, :endurance=>2, :heal=>nil, :history=>nil, :influence=>nil, :insight=>nil, :magicka=>nil, :perception=>nil, :riding=>nil, :stealth=>nil, :streetwise=>nil, :thievery=>nil}
你得到所有这些 nil 的原因是因为在你的语句中,如果 if 语句不为真,则结果为 nil。
例如:
[skill (mod += 2 if skill.to_s == player[:caste][:skill])]
将 return [the_skill, nil]
的情况 skill.to_s == player[:caste][:skill]
是不正确的
要查看发生了什么,请在 irb 中尝试此操作。
x = 0
=> 0
x += 1 if false
=> nil
x += 1 if true
=> 1
您可以使用类似的方法来解决这个问题。
[skill, skill.to_s == player[:caste][:skill] ? mod + 2 : mod ]
或使用上面的例子:
x = 0
=> 0
x = false ? x + 1 : x
=> 0
x = true ? x + 1 : x
=> 1
您的代码的以下修改版本应该可以工作。
player[:skills] = player[:skills].map do |skill, mod|
[skill, skill.to_s == player[:caste][:skill] || skill.to_s == player[:sub][:skill] ? mod + 2 : mod ]
end.to_h
然而,这里有一个稍微冗长,但希望更容易遵循的方法来完成你想做的事情,并允许在未来进行更多的修改,而不会让代码变得太混乱。
player = {
caste: {skill: "athletics"},
sub: {skill: "endurance"},
skills: {acrobatics: 0, athletics: 0, engineering: 0, endurance: 0, heal: 0, history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0, stealth: 0, streetwise: 0, thievery: 0},
}
player_caste_skill = player[:caste][:skill]
player_sub_skill = player[:sub][:skill]
current_skills = player[:skills]
updated_skills = {}
current_skills.each_pair do |skill, prev_value|
new_value = prev_value
case skill.to_s
when player_caste_skill, player_sub_skill
new_value = prev_value + 2
when "some_other_skill"
new_value = prev_value + 3
end
updated_skills[skill] = new_value
end
puts current_skills
puts updated_skills
我将默认值 (Hash#default) 设置为 player[:skill]
散列,只是为了避免在丢失密钥的情况下出错(它添加了密钥!!),还允许添加无需将每个技能初始化为 0 的新密钥。
player[:skills].default = 0
然后在一行中扫描需要递增的键:
[:caste, :sub].each { |key| player.dig(key, :skill).to_sym.then { |skill| player[:skills][skill] += 2 } }
由于初始化,您的播放器也可以
player = {
caste: {skill: "athletics"},
sub: {skill: "endurance"},
skills: {}
}
返回如下结果:
player #=> {:caste=>{:skill=>"athletics"}, :sub=>{:skill=>"endurance"}, :skills=>{:athletics=>2, :endurance=>2}}
其中:
player[:skills][:whatever] #=> 0
我会遍历定义的技能而不是技能值。
player.
map { |_, h| h[:skill] }.
compact.
map(&:to_sym).
each { |skill| player[:skills][skill] += 2 }
现在 player
已相应更新,您可以通过用 p player
或类似方法检查 player
来检查。
我正在制作一个简单的角色扮演游戏作为学习项目,但我对部分角色创建器有疑问。
此代码应确定分配给 player[:caste][:skill]
和 player[:sub][:skill]
的技能字符串,然后将 player[:skills]
中的每个技能值增加 2。无论什么字符串,此代码都应该有效赋值给player[:caste][:skill]
和player[:sub][:skill]
,只要等于player[:skills].to_s
即可。
目前,它只将更改应用到 player[:skills][:endurance]
而不是 player[:skills][:athletics]
。
player = {
caste: {skill: "athletics"},
sub: {skill: "endurance"},
skills: {acrobatics: 0, athletics: 0, engineering: 0, endurance: 0, heal: 0, history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0, stealth: 0, streetwise: 0, thievery: 0},
}
player[:skills] = player[:skills].map do |skill, mod|
[skill, (mod += 2 if skill.to_s == player[:caste][:skill])]
[skill, (mod += 2 if skill.to_s == player[:sub][:skill])]
end.to_h
换句话说,我的代码是 returning 以下 player[:skills]
散列:
skills: {acrobatics: 0, athletics: 0, engineering: 0, endurance: 2, heal: 0, history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0, stealth: 0, streetwise: 0, thievery: 0}
但我想要 return:
skills: {acrobatics: 0, athletics: 2, engineering: 0, endurance: 2, heal: 0, history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0, stealth: 0, streetwise: 0, thievery: 0}
如果有更简单的方法,请告诉我。我还尝试了以下方法:
player[:skills] = player[:skills].map do |skill, mod|
[skill, (mod += 2 if skill.to_s == (player[:caste][:skill] || player[:sub][:skill]))]
end.to_h
仅影响 player[:caste][:skill]
中的技能。
将代码更改为如下所示:
player = {
caste: {skill: "athletics"},
sub: {skill: "endurance"},
skills: {acrobatics: 0, athletics: 0, engineering: 0, endurance: 0, heal: 0,
history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0,
stealth: 0, streetwise: 0, thievery: 0},
}
player[:skills] = player[:skills].map do |skill, mod|
[skill, (mod += 2 if [player[:caste][:skill], player[:sub][:skill]].include?
(skill.to_s))]
end.to_h
你的代码不起作用的原因是映射 return 最后一行作为当前迭代的结果,所以在 athletics
的情况下,最后一行是
[skill, (mod += 2 if skill.to_s == player[:sub][:skill])]
将是错误的,这将是 nil
这就是为什么只有 endurance
案例有效。
希望对您有所帮助。
当我 运行 你的代码时,我得到了这个结果。
{:acrobatics=>nil, :athletics=>nil, :engineering=>nil, :endurance=>2, :heal=>nil, :history=>nil, :influence=>nil, :insight=>nil, :magicka=>nil, :perception=>nil, :riding=>nil, :stealth=>nil, :streetwise=>nil, :thievery=>nil}
那是因为 map return 执行了最后一条语句。另外,你实际上只在匹配子技能时为技能设置一个值,否则设置为零。
所以在您的代码中发生的事情是,每次迭代都是 returning 以下内容,这是传递到 map 的块中最后一条语句的结果。
[:acrobatics, nil]
[:athletics, nil]
[:engineering, nil]
[:endurance, 2]
[:heal, nil]
[:history, nil]
[:influence, nil]
[:insight, nil]
[:magicka, nil]
[:perception, nil]
[:riding, nil]
[:stealth, nil]
[:streetwise, nil]
[:thievery, nil]
最终结果是一个如下所示的数组。
[[:acrobatics, nil], [:athletics, nil], [:engineering, nil], [:endurance, 2], [:heal, nil], [:history, nil], [:influence, nil], [:insight, nil], [:magicka, nil], [:perception, nil], [:riding, nil], [:stealth, nil], [:streetwise, nil], [:thievery, nil]]
最终映射到一个新的散列
{:acrobatics=>nil, :athletics=>nil, :engineering=>nil, :endurance=>2, :heal=>nil, :history=>nil, :influence=>nil, :insight=>nil, :magicka=>nil, :perception=>nil, :riding=>nil, :stealth=>nil, :streetwise=>nil, :thievery=>nil}
你得到所有这些 nil 的原因是因为在你的语句中,如果 if 语句不为真,则结果为 nil。 例如:
[skill (mod += 2 if skill.to_s == player[:caste][:skill])]
将 return [the_skill, nil]
的情况 skill.to_s == player[:caste][:skill]
是不正确的
要查看发生了什么,请在 irb 中尝试此操作。
x = 0
=> 0
x += 1 if false
=> nil
x += 1 if true
=> 1
您可以使用类似的方法来解决这个问题。
[skill, skill.to_s == player[:caste][:skill] ? mod + 2 : mod ]
或使用上面的例子:
x = 0
=> 0
x = false ? x + 1 : x
=> 0
x = true ? x + 1 : x
=> 1
您的代码的以下修改版本应该可以工作。
player[:skills] = player[:skills].map do |skill, mod|
[skill, skill.to_s == player[:caste][:skill] || skill.to_s == player[:sub][:skill] ? mod + 2 : mod ]
end.to_h
然而,这里有一个稍微冗长,但希望更容易遵循的方法来完成你想做的事情,并允许在未来进行更多的修改,而不会让代码变得太混乱。
player = {
caste: {skill: "athletics"},
sub: {skill: "endurance"},
skills: {acrobatics: 0, athletics: 0, engineering: 0, endurance: 0, heal: 0, history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0, stealth: 0, streetwise: 0, thievery: 0},
}
player_caste_skill = player[:caste][:skill]
player_sub_skill = player[:sub][:skill]
current_skills = player[:skills]
updated_skills = {}
current_skills.each_pair do |skill, prev_value|
new_value = prev_value
case skill.to_s
when player_caste_skill, player_sub_skill
new_value = prev_value + 2
when "some_other_skill"
new_value = prev_value + 3
end
updated_skills[skill] = new_value
end
puts current_skills
puts updated_skills
我将默认值 (Hash#default) 设置为 player[:skill]
散列,只是为了避免在丢失密钥的情况下出错(它添加了密钥!!),还允许添加无需将每个技能初始化为 0 的新密钥。
player[:skills].default = 0
然后在一行中扫描需要递增的键:
[:caste, :sub].each { |key| player.dig(key, :skill).to_sym.then { |skill| player[:skills][skill] += 2 } }
由于初始化,您的播放器也可以
player = {
caste: {skill: "athletics"},
sub: {skill: "endurance"},
skills: {}
}
返回如下结果:
player #=> {:caste=>{:skill=>"athletics"}, :sub=>{:skill=>"endurance"}, :skills=>{:athletics=>2, :endurance=>2}}
其中:
player[:skills][:whatever] #=> 0
我会遍历定义的技能而不是技能值。
player.
map { |_, h| h[:skill] }.
compact.
map(&:to_sym).
each { |skill| player[:skills][skill] += 2 }
现在 player
已相应更新,您可以通过用 p player
或类似方法检查 player
来检查。