如何迭代集合的散列
How to iterate over a hash of sets
我有一个以游戏玩家的名字为键的散列,以及一个包含每个玩家被击败的其他玩家的名字作为值的集合对象。集合初始化为空,然后随机挑选两名玩家并互相战斗,获胜者将另一个玩家密钥添加到其集合中,代表战胜他们。胜利一旦确立,玩家就不能再互相争斗。最后,一个打败另一个的玩家也应该在他的设置上有被另一个打败的玩家,以及被他们打败的其他人,等等。
在给定的游戏情况下,有 5 名玩家,Claudia、Rosa、Bob、Carlos 和 Tim。假设 Rosa 打败了 Bob,然后 Bob 打败了 Carlos,Claudia 打败了 Tim,此时给定的数据将如下所示:
@match_data = {"claudia"=>#<Set: {"tim">,
"rosa"=>#<Set: {"bob", "carlos"}>,
"bob"=>#<Set: {"carlos"},
"carlos"=>#<Set: {},
"tim"=>#<Set: {}}
所以在这一点上,克劳迪娅战胜了蒂姆,所以他们不会再有一场战斗,罗莎战胜了鲍勃和卡洛斯,因此她永远不需要再和他们战斗,鲍勃战胜了卡洛斯,他们赢了战斗也一样。想象一下,在这之后,Bob打败了Claudia,此时想要的数据应该是:
@match_data = {"claudia"=>#<Set: {"tim"}>,
"rosa"=>#<Set: {"bob", "carlos", "claudia", "tim"}>,
"bob"=>#<Set: {"carlos", "claudia", "tim"},
"carlos"=>#<Set: {},
"tim"=>#<Set: {}}
当Bob打败Claudia时,他不仅获得了对她的胜利,还获得了对之前击败过的Tim的胜利,更重要的是,Rosa获得了对Claudia和Tim的胜利,因为她已经获得了对Bob的胜利.所以在这种情况下,Rosa 赢得了比赛,Bob 是第二名,其他人仍在比赛中。这可能会变得更复杂,因为玩家数量不受限制。
我试图克服的问题是创建一个函数来更新游戏状态。每次比赛结束时,此代码都会查看 match_data 并找出比赛结果获得了哪些胜利。这段代码是我的尝试之一:
def update_set(key)
store = Set.new
@match_data[key].each { |value| store.merge @match_data[value] }
if store.size > 0
store.each { |value| update_set(value) }
end
@match_data[key].merge store
end
@match_data.sort.map do |key, set|
update_set(key)
end
我的其他尝试得到一个错误,说我走得太深,或者我不能在循环中迭代散列。或者,我可以尝试使用另一种数据结构,但我不知道是哪一个。
编辑:为了清楚起见,我编辑了原始问题,因为在 运行 编译我的代码时不清楚我想要的输出是什么。尽管如此,@ddubs 给出的答案非常适合我的代码。
此外,我想指出我给出的示例中的一个错误,在我的程序中,数据永远无法真正完全按照第一个代码片段所示进行转换,因为所需的函数 运行 总是在每个代码片段之间战斗,刷新词典状态。我想我不想写太多无用的信息,让我的问题变得比需要的更复杂,但我最终压制了重要信息。
如果需要我可以post整个程序逻辑,但我不认为这是必要的。
EDIT2:添加了整个游戏逻辑,因为我发现它仍然不够清晰,@ddubs 给出的解决方案仍然有效,但也许有人可以提供更好的东西,现在已经提供了所有信息.
Set 看起来有点奇怪,或者可能只是 @match_data
对象的布局。无论如何,这个功能必须应用于每个玩家及其相应的集合。它还需要您将匹配数据也传递给它:
def compile_sets(set, data, results = Set.new)
set.each do |s|
results << s
results << compile_sets(data[s], data, results)
end
results.flatten
end
用法示例:
results = @match_data.map { |player,set| { player => compile_sets(set, @match_data) } }
p results
Returns:
[
{"carlos"=>#<Set: {}>},
{"bob"=>#<Set: {"carlos", "claudia"}>},
{"lisa"=>#<Set: {"bob", "carlos", "claudia"}>},
{"tim"=>#<Set: {"lisa", "bob", "carlos", "claudia"}>},
{"mary"=>#<Set: {"lisa", "bob", "carlos", "claudia"}>},
{"rosa"=>#<Set: {"tim", "lisa", "bob", "carlos", "claudia"}>},
{"claudia"=>#<Set: {}>}
]
我有一个以游戏玩家的名字为键的散列,以及一个包含每个玩家被击败的其他玩家的名字作为值的集合对象。集合初始化为空,然后随机挑选两名玩家并互相战斗,获胜者将另一个玩家密钥添加到其集合中,代表战胜他们。胜利一旦确立,玩家就不能再互相争斗。最后,一个打败另一个的玩家也应该在他的设置上有被另一个打败的玩家,以及被他们打败的其他人,等等。
在给定的游戏情况下,有 5 名玩家,Claudia、Rosa、Bob、Carlos 和 Tim。假设 Rosa 打败了 Bob,然后 Bob 打败了 Carlos,Claudia 打败了 Tim,此时给定的数据将如下所示:
@match_data = {"claudia"=>#<Set: {"tim">,
"rosa"=>#<Set: {"bob", "carlos"}>,
"bob"=>#<Set: {"carlos"},
"carlos"=>#<Set: {},
"tim"=>#<Set: {}}
所以在这一点上,克劳迪娅战胜了蒂姆,所以他们不会再有一场战斗,罗莎战胜了鲍勃和卡洛斯,因此她永远不需要再和他们战斗,鲍勃战胜了卡洛斯,他们赢了战斗也一样。想象一下,在这之后,Bob打败了Claudia,此时想要的数据应该是:
@match_data = {"claudia"=>#<Set: {"tim"}>,
"rosa"=>#<Set: {"bob", "carlos", "claudia", "tim"}>,
"bob"=>#<Set: {"carlos", "claudia", "tim"},
"carlos"=>#<Set: {},
"tim"=>#<Set: {}}
当Bob打败Claudia时,他不仅获得了对她的胜利,还获得了对之前击败过的Tim的胜利,更重要的是,Rosa获得了对Claudia和Tim的胜利,因为她已经获得了对Bob的胜利.所以在这种情况下,Rosa 赢得了比赛,Bob 是第二名,其他人仍在比赛中。这可能会变得更复杂,因为玩家数量不受限制。
我试图克服的问题是创建一个函数来更新游戏状态。每次比赛结束时,此代码都会查看 match_data 并找出比赛结果获得了哪些胜利。这段代码是我的尝试之一:
def update_set(key)
store = Set.new
@match_data[key].each { |value| store.merge @match_data[value] }
if store.size > 0
store.each { |value| update_set(value) }
end
@match_data[key].merge store
end
@match_data.sort.map do |key, set|
update_set(key)
end
我的其他尝试得到一个错误,说我走得太深,或者我不能在循环中迭代散列。或者,我可以尝试使用另一种数据结构,但我不知道是哪一个。
编辑:为了清楚起见,我编辑了原始问题,因为在 运行 编译我的代码时不清楚我想要的输出是什么。尽管如此,@ddubs 给出的答案非常适合我的代码。
此外,我想指出我给出的示例中的一个错误,在我的程序中,数据永远无法真正完全按照第一个代码片段所示进行转换,因为所需的函数 运行 总是在每个代码片段之间战斗,刷新词典状态。我想我不想写太多无用的信息,让我的问题变得比需要的更复杂,但我最终压制了重要信息。
如果需要我可以post整个程序逻辑,但我不认为这是必要的。
EDIT2:添加了整个游戏逻辑,因为我发现它仍然不够清晰,@ddubs 给出的解决方案仍然有效,但也许有人可以提供更好的东西,现在已经提供了所有信息.
Set 看起来有点奇怪,或者可能只是 @match_data
对象的布局。无论如何,这个功能必须应用于每个玩家及其相应的集合。它还需要您将匹配数据也传递给它:
def compile_sets(set, data, results = Set.new)
set.each do |s|
results << s
results << compile_sets(data[s], data, results)
end
results.flatten
end
用法示例:
results = @match_data.map { |player,set| { player => compile_sets(set, @match_data) } }
p results
Returns:
[
{"carlos"=>#<Set: {}>},
{"bob"=>#<Set: {"carlos", "claudia"}>},
{"lisa"=>#<Set: {"bob", "carlos", "claudia"}>},
{"tim"=>#<Set: {"lisa", "bob", "carlos", "claudia"}>},
{"mary"=>#<Set: {"lisa", "bob", "carlos", "claudia"}>},
{"rosa"=>#<Set: {"tim", "lisa", "bob", "carlos", "claudia"}>},
{"claudia"=>#<Set: {}>}
]