【问题标题】:Not getting proper iteration with yield with complex array of arrays使用复杂的数组数组没有得到正确的迭代
【发布时间】:2012-03-30 08:28:12
【问题描述】:
t = [
       [
         [["Armando", "P"],["Dave", "S"]],
         [["Richard", "R"],["Michael", "S"]],
       ],
       [
         [["Allen", "S"],["Omer", "P"]],
         [["David E.", "R"], ["Richard X.", "P"]]
       ]
    ]

def rps_game_winner(game)
    raise WrongNumberOfPlayersError unless game.length == 2
    if (game[0][1] =~ /[r]/i && game[1][1] =~ /[s]/i) || (game[0][1] =~ /[s]/i && game[1][1] =~ /[p]/i) || (game[0][1] =~ /[p]/i && game[1][1] =~ /[r]/i)
        return game[0]
    elsif (game[0][1] =~ /[r]/i && game[1][1] =~ /[p]/i) || (game[0][1] =~ /[s]/i && game[1][1] =~ /[r]/i) || (game[0][1] =~ /[p]/i && game[1][1] =~ /[s]/i)
        return game[1]
    elsif game[0][1] == game[1][1]
        return game[0]
    else
        raise NoSuchStrategyError.new
    end
end

def rps_tournament_winner(t)
   t.each do |pair|
    yield pair
   end  
end

rps_tournament_winner(t) { |x| rps_game_winner(x)  }

所以我得到的错误是:NoSuchStrategyError: NoSuchStrategyError - 这意味着产量正在将一个值传递给块,并且正在传递给我的方法 rps_game_winner 并且它正在评估某些东西并给出该错误 - 每个方法。

但它没有正确评估它....因为它应该查看 Armando and Dave 并返回一个获胜者,然后它应该返回并继续查看下一对并返回获胜者,等等。

附:当我做puts pair 时,我看到了正确的值——我已经在一对上测试了rps_game_winner 方法,它工作正常。它只是在多对上进行迭代,这给我带来了来回传递控制权的问题。

【问题讨论】:

  • 我认为你想提高WrongNumberOfPlayers.new,而不是WrongNumberOfPlayers(班级)。
  • @Linux_iOS.rb.cpp.c.lisp.m.sh:不,他没有。虽然两者都有效,并且实际上两者在语义上相同,但您的版本不是惯用的 Ruby。
  • @JörgWMittag:虽然它们是相同的,但我绝不会在任何代码中使用raise WrongNumberOfPlayers。虽然它有效,但我只是在查看一些代码,我会假设正在引发类对象。

标签: ruby yield


【解决方案1】:

在进行测试时,您的索引似乎不够深入。

rps_game_winner 的输入看起来像[[["Armando", "P"], ["Dave", "S"]], [["Richard", "R"], ["Michael", "S"]]]game[0][1] 看起来像 ["Dave", "S"]。您的正则表达式匹配看起来像是在尝试测试作为这些元组的第二个条目的字母。将你所有的 game[x][y] 更改为 game[x][y].last ,它可能会做你想做的事(我承认我很难理解你试图表达的逻辑)。您可以尝试让小对象(可能使用 Struct)更自然地表示您的数据,而不是使用深度嵌套的原始数据结构;通过为该数据结构中的条目提供合理的名称和结构,这将使您的代码更易于理解。

顺便说一句,您的正则表达式中不需要 [char] 类,实际上根本不需要正则表达式。 game[0][1].last.upcase == 'R'game[0][1].last =~ /[r]/i 更快更清晰。

【讨论】:

  • 使用.last 对我不起作用。当我只用一组 - [["Richard", "R"], ["Michael", "S"]] 测试它时,我收到此错误:NoMethodError: undefined method 'last' for "R":String 在一组上尝试时 - 这应该可以工作。
【解决方案2】:

你确定你的 t 是正确的吗? 在我看来应该是这样的:

t = [
      [["Armando", "P"],["Dave", "S"]],
      [["Richard", "R"],["Michael", "S"]],
      [["Allen", "S"],["Omer", "P"]],
      [["David E.", "R"], ["Richard X.", "P"]]
    ]

我假设 Armando 在第一场比赛中扮演 Dave。 理查德扮演迈克尔等人。

在您的代码中 [["Armando", "P"],["Dave", "S"]] 播放 [["Allen", "S"],["Omer", "P"]]。因此,当您的 rps_game_winner 检查 game[0][1] 时,它实际上返回 ["Dave", "S"]。不是P。

编辑1: 如果你想做你所说的设置逻辑,你需要像这样修改 rps_tournament_winner:

def rps_tournament_winner(t)
   t.each do |pair|
    pair.each do |g|
      puts 'winner:', yield(g)
    end
   end  
end

edit2: 做了我自己的实现。从中得到你想要的。但它会做你想做的事。 https://github.com/SpoBo/rock-paper-scissors

您基本上需要跟踪获胜者并让获胜者与自己对战。我的实现允许任意数量的玩家互相对抗。我的实现的唯一问题是玩家总是玩同一手牌,一旦 2 名玩家用同一手牌相遇,游戏就会变得不可预测。所以它需要一些修改来处理这个问题。

【讨论】:

  • 是的,t 是正确的..这就是原因。有两轮。所以阿曼多扮演戴夫,戴夫赢了。然后理查德扮演迈克尔,理查德获胜。然后戴夫(第一盘的获胜者)扮演理查德(第二盘的获胜者)。该获胜者现在是第 1 轮的获胜者,然后必须继续与第 2 轮的获胜者比赛以确定锦标赛获胜者。所以是的,这有点令人困惑......但t 是正确的。
  • 获胜者:Dave S 获胜者:Richard R 获胜者:Allen S 获胜者:Richard X. P
  • 这就是我修改t我的方式时得到的结果。我在您的代码中看不到任何“设置逻辑”。您的代码只希望游戏存在 2 个数组。每个数组都包含一个名称和一个“手”。
  • 您的t 仍然是错误的。基本上应该有两轮 - 每轮有 4 名玩家。因此,Armando、Dave、Richard 和 Michael 在一轮中,其余的则在另一轮中。我现在面临的问题是使用第一轮获胜者的子数组格式化另一个包含两个元素的数组。
  • 修改了我的答案。做了我自己的实现,因为显然我没有更好的事情可做;p 不过是一个有趣的练习。
猜你喜欢
  • 1970-01-01
  • 2012-11-10
  • 2017-03-14
  • 2017-08-16
  • 1970-01-01
  • 2020-03-22
  • 2022-10-07
  • 2011-08-24
  • 2021-05-28
相关资源
最近更新 更多