我写的算法,创建和排序的基础上匹配数据的世界杯小组表。因此,考虑以下的比赛数据:
[ {ID:1,home_team:洪都拉斯,away_team:智利,home_score:0,away_score:1}, {ID:2,home_team:西班牙,away_team:瑞士,home_score:0,away_score:1}, {ID:3,home_team:智利,away_team:瑞士,home_score:1,away_score:0}, {ID:4,home_team:西班牙,away_team:洪都拉斯,home_score:2,away_score:0}, {ID:5,home_team:智利,away_team:西班牙,home_score:1,away_score:2}, {ID:6,home_team:洪都拉斯,away_team:瑞士,home_score:0,away_score:0} ]
我的程序会产生这样(顺序很重要):
[{goals_for:4,goals_against:2,goal_diff:2,积分:6,名称:西班牙}, {goals_for:3,goals_against:2,goal_diff:1,积分:6,名称:智利}, {goals_for:1,goals_against:1,goal_diff:0分:4,名称:瑞士}, {goals_for:0,goals_against:3,goal_diff:-3,要点:1,名称:洪都拉斯}]这是伟大的,除非有两路或三路领带。然后,标准变得复杂。这是命令precedence:
- 如果有一搭下面是使用
我的排序功能满足前三个标准。我怎样才能改变它占到情况下,有一个双向或三路领带?
高清排序 teams.sort_by!做|团队| [队[:分],团队[:goal_diff],团队[:goals_for] end.reverse! 结束的3路实施例领带
[ {ID:1,home_team:阿尔及利亚,away_team:斯洛文尼亚,home_score:2,away_score:1}, {ID:2,home_team:USA,away_team:斯洛文尼亚,home_score:5,away_score:1}, {ID:3,home_team:英格兰队,away_team:斯洛文尼亚,home_score:4,away_score:0}, {ID:4,home_team:阿尔及利亚,away_team:USA,home_score:3,away_score:0}, {ID:5,home_team:USA,away_team:英格兰队,home_score:2,away_score:0}, {ID:6,home_team:英格兰队,away_team:阿尔及利亚,home_score:3,away_score:2} ]根据标准1(分)本例将消除斯洛文尼亚。
其余三支球队的行列,然后计算基于匹配数据的子集。这个子集应该只包括并列队之间的比赛。在这种情况下,我们会重建使用所有,包括阿尔及利亚,英格兰和美国的比赛表。我们排除涉及到斯洛文尼亚的比赛。
表应该是这样的:
| POS机| TEAM | GF | GA | GD |点| | 1 |阿尔及利亚| 5 | 3 | 2 | 3 | | 3 |英格兰| 3 | 4 | -1 | 3 | | 2 |美国| 2 | 3 | -1 | 3 |
阿尔及利亚胜净胜球(标准5)。英格兰需要第二的位置,因为它的目标大于对美国(标准6)。
我的程序实际输出这一点,这是不正确的,因为它不做些什么的关系,并停止在标准3。
[{goals_for:7,goals_against:4,goal_diff:3,积分:6,名称:英格兰队}, {goals_for:7,goals_against:4,goal_diff:3,积分:6,名称:阿尔及利亚}, {goals_for:7,goals_against:4,goal_diff:3,积分:6,名称:USA}, {goals_for:2,goals_against:11,goal_diff:-9分:0,名称:斯洛文尼亚}]下面是完整的程序:
类计算器 attr_reader:游戏:团队 高清初始化(游戏) 默认值= {goals_for:0,goals_against:0,goal_diff:0分:0} @games =游戏 @teams = games.each_with_object([])做|游戏,编曲| arr.push({名称:游戏[:home_team]}!.merge(默认)) arr.push({名称:游戏[:away_team]}!.merge(默认)) end.uniq 结束 高清build_table 建立 分类 返回球队 结束 私人 DEF建设 games.each做|游戏| 如果游戏[:home_score]。present? &功放;&安培;游戏[:away_score]。present? home_team = teams.detect {|团队|团队[:名称] ==游戏[:home_team]} away_team = teams.detect {|团队|团队[:名称] ==游戏[:away_team]} home_team [:goals_for] + =游戏[:home_score] home_team [:goals_against] + =游戏[:away_score] away_team [:goals_for] + =游戏[:away_score] away_team [:goals_against] + =游戏[:home_score] home_team [:goal_diff] = home_team [:goals_for] - home_team [:goals_against] away_team [:goal_diff] = away_team [:goals_for] - away_team [:goals_against] 如果游戏[:home_score]>游戏[:away_score] home_team [:分] + = 3 ELSIF游戏[:home_score]<游戏[:away_score] away_team [:分] + = 3 其他 home_team [:分] + = 1 away_team [:分] + = 1 结束 结束 结束 结束 高清排序 teams.sort_by! {|团队| [队[:分],团队[:goal_diff],团队[:goals_for]} .reverse! 结束 结束解决方案
您有一组明确定义的规则,以确定这些队要责令。一种方法是编写实现这些规则一次,和短路一种常规的,当它发现一个胜利者:
高清compare_points(A,B) 一个[:分]< => B〔:分] 结束 高清compare_goal_diff(A,B) 一个[:goal_diff]< => B〔:goal_diff] 结束 高清compare_teams(A,B) 比较= compare_points(A,B) 返回的比较除非comparison.zero? 比较= compare_goal_diff(A,B) 返回的比较除非comparison.zero? 每种类型的比较#重复 #... comparison.zero? ? flip_coin:比较 结束 teams.sort! {| A,B | compare_teams(A,B)} .reverse!在比较单一的值(如分),比较操作符< => 就足够了。对于更复杂的比较,你需要深入到 @games 数组来决定胜负,如:
高清compare_points_from_matches_between(A,B) #挥手如下 # 外壳 #当A队比在他们的会议B队少点 #-1 #当B队比在他们的会议A队少点 #1 # 其他 #0 # 结束 结束
根据您的规则逐一比较。在每个如果比较步骤非零返回该值;否则,你继续前进的下一个步骤。在年底,如果比较仍然是零,你掷硬币。
I'm writing an algorithm to create and sort a World Cup group table based on match data. So, given the following match data:
[ { id: 1, home_team: "Honduras", away_team: "Chile", home_score: 0, away_score: 1 }, { id: 2, home_team: "Spain", away_team: "Switzerland", home_score: 0, away_score: 1 }, { id: 3, home_team: "Chile", away_team: "Switzerland", home_score: 1, away_score: 0 }, { id: 4, home_team: "Spain", away_team: "Honduras", home_score: 2, away_score: 0 }, { id: 5, home_team: "Chile", away_team: "Spain", home_score: 1, away_score: 2 }, { id: 6, home_team: "Honduras", away_team: "Switzerland", home_score: 0, away_score: 0 } ]My program will produce this (order is important):
[{ goals_for: 4, goals_against: 2, goal_diff: 2, points: 6, name: "Spain" }, { goals_for: 3, goals_against: 2, goal_diff: 1, points: 6, name: "Chile" }, { goals_for: 1, goals_against: 1, goal_diff: 0, points: 4, name: "Switzerland" }, { goals_for: 0, goals_against: 3, goal_diff: -3, points: 1, name: "Honduras" }]This is great, unless there is a two-way or a three-way tie. Then the criteria becomes complex. Here it is in order of precedence:
- IF there is a tie the following is used
Question
My sorting function satisfies the first three criteria. How can I change it to account for cases where there is a two-way or a three-way tie?
def sort teams.sort_by! do |team| [ team[:points], team[:goal_diff], team[:goals_for] ] end.reverse! endExample of 3-way tie
[ { id: 1, home_team: "Algeria", away_team: "Slovenia", home_score: 2, away_score: 1 }, { id: 2, home_team: "USA", away_team: "Slovenia", home_score: 5, away_score: 1 }, { id: 3, home_team: "England", away_team: "Slovenia", home_score: 4, away_score: 0 }, { id: 4, home_team: "Algeria", away_team: "USA", home_score: 3, away_score: 0 }, { id: 5, home_team: "USA", away_team: "England", home_score: 2, away_score: 0 }, { id: 6, home_team: "England", away_team: "Algeria", home_score: 3, away_score: 2 } ]This example would eliminate Slovenia based on criteria 1 (points).
The ranks of the remaining three teams are then calculated based on a subset of the match data. This subset should only include matches between the tied teams. In this case, we would rebuild the table using all matches that include Algeria, England, and the USA. We exclude matches involving Slovenia.
The table should look like this:
| POS | TEAM | GF | GA | GD | POINTS | | 1 | Algeria | 5 | 3 | 2 | 3 | | 3 | England | 3 | 4 | -1 | 3 | | 2 | USA | 2 | 3 | -1 | 3 |Algeria wins on goal difference (criteria 5). England takes second spot because its goals for is greater than that of the USA (criteria 6).
My program actually outputs this, which is not correct, as it does not do anything about ties, and stops at criteria 3.
[ { goals_for: 7, goals_against: 4, goal_diff: 3, points: 6, name: "England" }, { goals_for: 7, goals_against: 4, goal_diff: 3, points: 6, name: "Algeria" }, { goals_for: 7, goals_against: 4, goal_diff: 3, points: 6, name: "USA" }, { goals_for: 2, goals_against: 11, goal_diff: -9, points: 0, name: "Slovenia" }]Here is the full program:
class Calculator attr_reader :games, :teams def initialize(games) defaults = { goals_for: 0, goals_against: 0, goal_diff: 0, points: 0 } @games = games @teams = games.each_with_object([]) do |game, arr| arr.push({ name: game[:home_team] }.merge!(defaults)) arr.push({ name: game[:away_team] }.merge!(defaults)) end.uniq end def build_table build sort return teams end private def build games.each do |game| if game[:home_score].present? && game[:away_score].present? home_team = teams.detect { |team| team[:name] == game[:home_team] } away_team = teams.detect { |team| team[:name] == game[:away_team] } home_team[:goals_for] += game[:home_score] home_team[:goals_against] += game[:away_score] away_team[:goals_for] += game[:away_score] away_team[:goals_against] += game[:home_score] home_team[:goal_diff] = home_team[:goals_for] - home_team[:goals_against] away_team[:goal_diff] = away_team[:goals_for] - away_team[:goals_against] if game[:home_score] > game[:away_score] home_team[:points] += 3 elsif game[:home_score] < game[:away_score] away_team[:points] += 3 else home_team[:points] += 1 away_team[:points] += 1 end end end end def sort teams.sort_by! { |team| [ team[:points], team[:goal_diff], team[:goals_for] ] }.reverse! end end解决方案
You have a set of well-defined rules to determine how the teams should be ordered. One approach is to write a sort routine that implements those rules one at a time, and short-circuits when it finds a winner:
def compare_points(a, b) a[:points] <=> b[:points] end def compare_goal_diff(a, b) a[:goal_diff] <=> b[:goal_diff] end def compare_teams(a, b) comparison = compare_points(a, b) return comparison unless comparison.zero? comparison = compare_goal_diff(a, b) return comparison unless comparison.zero? # Repeat for each type of comparison # ... comparison.zero? ? flip_coin : comparison end teams.sort! { |a, b| compare_teams(a, b) }.reverse!When comparing single values (like points), the comparison operator <=> is enough. For the more complex comparisons you'll need to dig into the @games array to determine the winner, e.g.:
def compare_points_from_matches_between(a, b) # Hand-waving follows # case # when team A has fewer points than team B in their meetings # -1 # when team B has fewer points than team A in their meetings # 1 # else # 0 # end endApply each comparison according to your rules. At each step if the comparison is non-zero you return that value; otherwise you move on the the next step. At the end if the comparison is still zero you flip a coin.
更多推荐
如何在Ruby中一个世界杯小组表进行排序
发布评论