我写了相同的if语句5次,我怎么能重写这个只有一个if语句



我有以下数据库列team_a_set_1,team_a_set_2,team_a_set_3,team_a_set_4,team_a_set_5,team_b_set_1,team_b_set_2,team_b_set_3,team_b_set_4,team_b_set_5。我使用这些列来存储5局网球比赛的结果。

现在我试着找出谁是team ateam b之间的赢家。谁赢的局数最多,谁就是赢家。我的代码大致如下

def find_winner
team_a_win_count = 0
team_b_win_count = 0
if team_a_set_1.present? && team_b_set_1.present?
if team_a_set_1 > team_b_set_1
team_a_win_count = team_a_win_count + 1
elsif team_b_set_1 > team_a_set_1
team_b_win_count = team_b_win_count +1
end
end
if team_a_set_2.present? && team_b_set_2.present?
if team_a_set_2 > team_b_set_2
team_a_win_count = team_a_win_count + 1
elsif team_b_set_2 > team_a_set_2
team_b_win_count = team_b_win_count +1
end
end
if team_a_set_3.present? && team_b_set_3.present?
if team_a_set_3 > team_b_set_3
team_a_win_count = team_a_win_count + 1
elsif team_b_set_3 > team_a_set_3
team_b_win_count = team_b_win_count +1
end
end
if team_a_set_4.present? && team_b_set_4.present?
if team_a_set_4 > team_b_set_4
team_a_win_count = team_a_win_count + 1
elsif team_b_set_4 > team_a_set_4
team_b_win_count = team_b_win_count +1
end
end
if team_a_set_5.present? && team_b_set_5.present?
if team_a_set_5 > team_b_set_5
team_a_win_count = team_a_win_count + 1
elsif team_b_set_5 > team_a_set_5
team_b_win_count = team_b_win_count +1
end
end
if team_a_win_count > team_b_win_count
puts 'Team A won'
elsif team_b_win_count > team_a_win_count
puts 'Team B won'
else
puts 'Draw'
end
end

正如你所看到的,我在if语句中重复了5次相同的逻辑。我想重构这段代码,这样我就不用重复同样的事情5次了。我试过这样做,但它不起作用

1.upto(5) do |n|
if "team_a_set_#{n}".present? && "team_b_set_#{n}".present?
if "team_a_set_#{n}" > "team_b_set_#{n}"   # this is not working because it's comparing string
team_a_win_count = team_a_win_count + 1
elsif "team_b_set_#{n}" > "team_a_set_#{n}"
team_b_win_count = team_b_win_count + 1
end
end
end

那么我如何重构这段代码,这样我就不需要写5次if语句了?

根据每个人的建议,我最终重新设计了我的数据库。现在我在哈希中存储集合。现在一切看起来又好又干净。

这里的答案最有可能是更好地建模数据。

class Game < ApplicationRecord
belongs_to :player_a, class_name: 'Player'
belongs_to :player_b, class_name: 'Player'
has_many :game_sets
end
# rails g model game_set game:belongs_to player_a_score:integer player_b_score:integer
class GameSet < ApplicationRecord
belongs_to :game
end

这设置了一个简单的一对多,而不是有N个列。这使您可以通过选择聚合来简单地汇总行:

Game.select(
'games.*',
'SUM(
SELECT 1 FROM gamesets gs WHERE gs.game_id = games.id AND gs.player_a_score > gs.player_b_score
) AS player_a_wins',
'SUM(
SELECT 1 FROM gamesets gs WHERE gs.game_id = games.id AND gs.player_b_score > gs.player_a_score
) AS player_b_wins',
'SUM(
SELECT 1 FROM gamesets gs WHERE gs.game_id = games.id AND gs.player_b_score = gs.player_a_score
) AS draws'
)

你也可以把结果缓存到game_sets表中:

class GameSet < ApplicationRecord
belongs_to :game
belongs_to :winner, 
class_name: 'Player',
optional: true # nil for draws
end
还有一长串更高效的方法来获取聚合,比如在Postgres或横向连接上使用FILTER。您还应该考虑将游戏结果直接保存在游戏表中,以获得更好的读取性能。

正如我之前提到的,当您发现自己在变量名中添加整数后缀时,我认为我应该使用数组。类似地,如果您发现自己使用字符串前缀或后缀,则应该使用散列。

代码的编写方式,很难遵循逻辑,并且在不了解更多的情况下,很难提出具体的建议,但是,如果您可以获得以下格式的数据:

games = [
{
'a' => [12, 34, 56, 78, 90],
'b' => [21, 43, 65, 87, 9],
},
{
'a' => [1, 2, 3, 4, 5],
'b' => [5, 4, 2, 2, 1],
},
]
games.each_index do |g|
game = games[g]
teams = game.keys
wins = Hash[teams.map {|t| [t, 0]}]
game[teams[0]].each_index do |i|
winner = game[teams[0]][i] > game[teams[1]][i] ? 0 : 1
wins[teams[winner]] += 1
end
puts "Winner of game #{g}: #{teams[wins[teams[0]] > wins[teams[1]] ? 0 : 1]}"
end

你将拥有能够处理任意团队之间任意数量的游戏的优势。同时,你也不需要修改代码来处理不同的游戏/团队引用方式。

有以下数据库列team_a_set_1,team_a_set_2,team_a_set_3,team_a_set_4,team_a_set_5,team_b_set_1,team_b_set_2,team_b_set_3,team_b_set_4,team_b_set_5

这真的是你的问题。数据库的设计并不适合做这类事情。实际上,如果表GAMES的列是:game,set,team,score,那么您就不需要编写任何Ruby来完成此操作。

最新更新