如何根据其评分将所有成员划分为各个公平团队?

时间:2019-04-10 04:09:18

标签: ruby-on-rails ruby algorithm

我想根据球员的排名将他们分成各个公平的团队。例如,我有一个这样的球员名单:

players = [{
    name: "Qasim",
    rating: 1
  }, {
    name: "Mahsam",
    rating: 7
  }, {
    name: "Aj",
    rating: 3
  }, {
    name: "Osman",
    rating: 6
  }, {
    name: "Usama",
    rating: 2
  }, {
    name: "Bilal",
    rating: 8
  }, {
    name: "Kaka",
    rating: 20
  }, {
    name: "Owen",
    rating: 15
  }
]

我想将他们分为4个小组,这些小组的平均总成绩最好,并且在这样的成员中也一样:

Team A       Team B       Team C     Team D
=======      =======      =======    =======
Kaka: 20     Owen: 15     Bilal: 8   Mahsam: 7
Qasim: 1     Usama: 2     Aj: 3      Osman: 6

我找到了解决此问题的方法,但是很难将其转换为ruby代码。假设我们可以拥有8个以上的玩家,并且团队数量可以从2到4个团队变化。

1. Sort all players by their ratings descendingly.
2. Assign team A the best player.
3. Assign team B the next best player.
4. Assign team C the next best player.
5. Assign team D the next best player.
6. Assign team D the next best player.
7. Assign team C the next best player.
8. Assign team B the next best player.
9. Assign team A the next best player.
10. Go to 2
11. End when we're out of players.

有人可以帮忙吗?谢谢你。

注意:实际上,该团队可以从2到4个团队变化,每个团队中的所有玩家必须相等,并且每个团队的总评分必须相等或尽可能接近相等。

玩家可以是任何数字,并且必须被团队整除。

EX:如果有2支队伍,则总人数必须为偶数。如果3支球队,则总人数必须被3除;如果4支球队,则总人数必须被4除。欢迎任何类型的答案:)

2 个答案:

答案 0 :(得分:3)

您可以实现如下所述的分配算法。

def assign(nbr_teams, players)
  flip = [true, false].cycle
  players.
    sort_by { |p| p[:rating] }.
    each_slice(nbr_teams).
    map { |a| flip.next ? a.reverse : a }.
    transpose
end

assign(4, players)
  #=> [[{:name=>"Osman",  :rating=>6}, {:name=>"Mahsam", :rating=>7}],
  #    [{:name=>"Aj",     :rating=>3}, {:name=>"Bilal",  :rating=>8}],
  #    [{:name=>"Usama",  :rating=>2}, {:name=>"Owen",   :rating=>15}],
  #    [{:name=>"Qasim",  :rating=>1}, {:name=>"Kaka",   :rating=>20}]] 

如果有2个团队,任务将如下。

assign(2, players)
  #=> [[{:name=>"Usama",  :rating=>2}, {:name=>"Aj",     :rating=>3},
  #     {:name=>"Bilal",  :rating=>8}, {:name=>"Owen",   :rating=>15}],
  #    [{:name=>"Qasim",  :rating=>1}, {:name=>"Osman",  :rating=>6},
  #     {:name=>"Mahsam", :rating=>7}, {:name=>"Kaka",   :rating=>20}]]

步骤如下。

nbr_teams = 4
flip = [true, false].cycle
  #=> #<Enumerator: [true, false]:cycle>

Array#cycle的工作方式如下:flip.next #=> trueflip.next #=> falseflip.next #=> true,依此类推。继续

a = players.sort_by { |p| p[:rating] }
  #=> [{:name=>"Qasim",  :rating=>1},  {:name=>"Usama", :rating=>2},
  #    {:name=>"Aj",     :rating=>3},  {:name=>"Osman", :rating=>6},
  #    {:name=>"Mahsam", :rating=>7},  {:name=>"Bilal", :rating=>8},
  #    {:name=>"Owen",   :rating=>15}, {:name=>"Kaka", :rating=>20}] 
b = a.each_slice(nbr_teams)
  #=> #<Enumerator:
  #     [{:name=>"Qasim",  :rating=>1},  {:name=>"Usama", :rating=>2},
  #      {:name=>"Aj",     :rating=>3},  {:name=>"Osman", :rating=>6},
  #      {:name=>"Mahsam", :rating=>7},  {:name=>"Bilal", :rating=>8},
  #      {:name=>"Owen",   :rating=>15}, {:name=>"Kaka",  :rating=>20}]
  #     :each_slice(4)> 

我们可以将此枚举器转换为数组,以查看它将生成的对象并传递给map

b.to_a
  #=> [[{:name=>"Qasim",  :rating=>1},  {:name=>"Usama", :rating=>2},
  #     {:name=>"Aj",     :rating=>3},  {:name=>"Osman", :rating=>6}], 
  #    [{:name=>"Mahsam", :rating=>7},  {:name=>"Bilal", :rating=>8}, 
  #     {:name=>"Owen",   :rating=>15}, {:name=>"Kaka",  :rating=>20}]] 

继续

c = b.map { |a| flip.next ? a.reverse : a }
  #=> [[{:name=>"Osman",  :rating=>6},  {:name=>"Aj",    :rating=>3},
  #     {:name=>"Usama",  :rating=>2},  {:name=>"Qasim", :rating=>1}],
  #    [{:name=>"Mahsam", :rating=>7},  {:name=>"Bilal", :rating=>8},
  #     {:name=>"Owen",   :rating=>15}, {:name=>"Kaka",  :rating=>20}]] 
c.transpose
  #=> [[{:name=>"Osman", :rating=>6}, {:name=>"Mahsam", :rating=>7}],
  #    [{:name=>"Aj",    :rating=>3}, {:name=>"Bilal",  :rating=>8}],
  #    [{:name=>"Usama", :rating=>2}, {:name=>"Owen",   :rating=>15}],
  #    [{:name=>"Qasim", :rating=>1}, {:name=>"Kaka",   :rating=>20}]] 

可能希望将结果转换为哈希数组。

assign(4, players).map { |a| a.map { |h| [h[:name], h[:rating]] }.to_h }
  #=> [{"Osman"=>6, "Mahsam"=>7},
  #    {"Aj"   =>3, "Bilal" =>8},
  #    {"Usama"=>2, "Owen"  =>15},
  #    {"Qasim"=>1, "Kaka"  =>20}] 

答案 1 :(得分:1)

我们可以解决通过按键等级对哈希进行排序的问题

players.sort_by { |k| k[:rating] }

现在对数组进行排序。

您最多可以迭代数组长度的一半,并在一个团队中推入i元素和length-i元素,在这种情况下,您有4个团队。

def divide_teams players
   players = players.sort_by { |k| k[:rating] } # sorted
   len = players.length
   teams = Hash.new(0)
   (len/2).times do |i|
      teams["team#{i+1}"] = [players[i], players[len-i-1]]
   end
   teams
end

divide_teams players

=> {"team1"=>[{:name=>"Qasim", :rating=>1}, {:name=>"Kaka", :rating=>20}],
 "team2"=>[{:name=>"Usama", :rating=>2}, {:name=>"Owen", :rating=>15}],
 "team3"=>[{:name=>"Aj", :rating=>3}, {:name=>"Bilal", :rating=>8}],
 "team4"=>[{:name=>"Osman", :rating=>6}, {:name=>"Mahsam", :rating=>7}]}

我假设现在有4个团队,每个团队中有2个成员。

如果职能团队是一个动态变量,则可以根据需要更改职能。

谢谢。