Ruby:访问数组中的数组

时间:2013-10-23 06:15:42

标签: ruby arrays recursion

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

这是一场需要通过以下代码解决的锦标赛:

def self.winner(player1, player2)
  p1c = player1.last.downcase
  p2c = player2.last.downcase
  unless RPS.include?(p1c) && RPS.include?(p2c)
    raise NoSuchStrategyError, "Strategy must be one of R,P,S"
  end
  if p1c!=p2c 
    case p1c
      when "r" 
        p2c=="s" ? player1 : player2
      when "p" 
        p2c=="r" ? player1 : player2
      when "s" 
        p2c=="p" ? player1 : player2
    end
   else 
     player1
  end  
end

现在基本情况是

def self.tournament_winner(tournament)
  if tournament.size == 2
    self.winner(tournament[0], tournament[1])
  else
    #WORK HERE
  end
end

但是在 else 中如何让第一个数组成为包含“Armando”和“Dave”的数组,检查谁赢了然后继续,它需要在任意大小的数组上使用。 有没有办法通过元素并过滤胜利;即,  在第一个递归实例上它应该返回:

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

如果我的措辞不好,我很抱歉。我一直试图解决这个问题一段时间,而且迟到了,我缺乏感觉。

1 个答案:

答案 0 :(得分:2)

该基本功能不正确。首先,让我们假设tourney数组是格式良好的,总是成对的玩家或阵列。你想要做的是如果tournament[0]是一个简单的玩家定义,那么玩家1是tournament[0]。但是,如果tournament[0]是一系列玩家,则玩家1是tournament[0]的赢家 - 这是您的递归。对玩家2重复相同的逻辑,并返回玩家1与玩家2的获胜者。

现在,问题变成“我如何确定tournament[0]是否是一个简单的数组?”让我们使用交互式shell(我更喜欢pry而非默认irb),使用您的第二个示例执行此操作:

[3] pry(main)> tourney.class
=> Array
[4] pry(main)> tourney[0].class
=> Array
[5] pry(main)> tourney[0][0].class
=> Array
[6] pry(main)> tourney[0][0][0].class
=> String

因此,我们可以测试.class方法来检查它是否是一个数组,从而引导我们找到这个解决方案:

def self.tournament_winner(tournament)
  if tournament[0][0].class == Array
    player1 = self.tournament_winner(tournament[0])
  else
    player1 = tournament[0]
  end
  if tournament[1][0].class == Array
    player2 = tournament_winner(tournament[1])
  else
    player2 = tournament[1]
  end

  self.winner(player1, player2)
end

请注意,我需要使用tournament[0][0]来阻止我们过一步递归。实际上,我不喜欢这样,所以让我们以另一种方式尝试,使用上面建议的flatten。如果扁平化阵列与未展开版本的大小相同,我们已到达树的底部:

def self.tournament_winner(tournament)
  if tournament[0].flatten(1).size != tournament[0].size
    player1 = self.tournament_winner(tournament[0])
  else
    player1 = tournament[0]
  end
  if tournament[1].flatten(1).size != tournament[1].size
    player2 = tournament_winner(tournament[1])
  else
    player2 = tournament[1]
  end

  self.winner(player1, player2)
end

我使用flatten(1)作为次要优化。现在:

[7] pry(main)> puts "And the winner is #{tournament_winner(tourney)[0]}!"
=> And the winner is Richard!

上述函数的进一步Ruby-fication可能是

def self.tournament_winner(tournament)
  player1 = if tournament[0].flatten(1).size != tournament[0].size
              self.tournament_winner(tournament[0])
            else
              tournament[0]
            end
  player2 = if tournament[1].flatten(1).size != tournament[1].size
              tournament_winner(tournament[1])
            else
              tournament[1]
            end

  self.winner(player1, player2)
end

或者让DRYer:

def self.get_competitor(branch)
  if branch.flatten(1).size != branch.size
    self.tournament_winner(branch)
  else
    branch
  end
end

def self.tournament_winner(tournament)
  player1 = self.get_competitor(tournament[0])
  player2 = self.get_competitor(tournament[1])

  self.winner(player1, player2)
end