如何在Ruby中一个世界杯小组表进行排序世界杯、小组、如何在、Ruby

2023-09-11 05:54:00 作者:靠谱的小男生

我写的算法,创建和排序的基础上匹配数据的世界杯小组表。因此,考虑以下的比赛数据:

  [
  {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!
  结束
 
菲律宾男篮派出国家队球员出战3X3篮球世界杯 布莱切替身在列

的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:

Greatest number of points Greatest goal diff Greatest goals for IF there is a tie the following is used Greatest number of points from matches between tied teams Greatest goal diff from matches between tied teams Greatest goals score from matches between tied teams Draw lots

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!
  end

Example 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
  end

Apply 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.