如何按比例排序,同时避免除零?

时间:2013-01-25 20:57:29

标签: ruby algorithm sorting

考虑一个类Team,类变量'wins'和'loss'。我希望通过胜利:损失率对一系列团队进行排序,以便:

5:0> 3:0> 1:0> 3:1> 5:5> 3:3> 1:3> 0:1> 0:3> 0:5

我已经有一个(部分)黑客攻击解决方案,我不满意,我想知道是否有更清洁/更优雅/更简单的方法来解决这个问题。

def ratio
    if @losses == 0 then 
        return 1000000+@wins
    end
    if @wins == 0 then
        return 0-@losses
    end
    return @wins/@losses
end

(这不能解决5:5> 3:3)

哪个属于Team类,可以像这样使用:

teams.sort! { |a, b| b.ratio <=> a.ratio }

解决这个问题最简单的方法是什么? (解决方案不一定是Ruby,我对任何OO都很满意)

7 个答案:

答案 0 :(得分:3)

我不会说Ruby,但是一种可以提供所需结果的Python方法会使用一个元组作为一个键(在decorate-sort-undecorate中使用“Schwartzian变换”这个习语。)

例如,您可以按胜利分数,然后是胜利数,然后(负数)损失排名,这将给出您想要的排序:

>>> wl = [[3, 0], [3, 1], [0, 5], [3, 3], [0, 3], [5, 5], [1, 3], [5, 0]]
>>> 
>>> def rank(wl):
...     win, loss = wl
...     return (1.0*win/(win+loss) if win+loss > 0 else 0), win, -loss
... 
>>> sorted(wl, key=rank)
[[0, 5], [0, 3], [1, 3], [3, 3], [5, 5], [3, 1], [3, 0], [5, 0]]
>>> sorted(wl, key=rank)[::-1]
[[5, 0], [3, 0], [3, 1], [5, 5], [3, 3], [1, 3], [0, 3], [0, 5]]

不幸的是,我不知道Ruby的等价物是什么,但我知道有一个sort_by方法在某处浮动。

答案 1 :(得分:2)

为什么不覆盖sort_by而不是定义与<=>一起使用的方法,以便它处理比较,然后你可以避免创建一个数字,而是做类似的事情

def <=>(other)
  if losses == 0
    -1
  elsif other.losses == 0
    1
  else
    # do ratio logic here
  end
end

答案 2 :(得分:1)

每个团队都有一个胜率,并为此排序。在每个胜率中,你应该根据比赛总数进行排序,确定总比赛的好坏取决于球队的整体胜率是否小于或大于50%。

答案 3 :(得分:1)

(@wins * 3 + 1) / (@losses * 3 + 2)

5:0 8.00
3:0 5.00
3:1 2.00
5:5 0.94
3:3 0.91
1:3 0.36
0:3 0.09
0:5 0.06

答案 4 :(得分:0)

基于上述评论,我同意单个可排序的数字可以很好地运作。也许是这样的事情:

def win_loss_ranking
  (@wins *2 ) - (@losses * 2) + (@wins + @losses)
end

这会给你一个考虑到比赛以及输赢的数字。所以在你的情况下有5:5和3:3,5:5的win_loss_ranking为10,3:3的团队有6。

答案 5 :(得分:0)

比率(在与您的目的相关的意义上)相对于差异会单调增加。为什么不使用差异来实现它?

class Team
  def difference; @wins - @losses end
end

teams.sort!{|a, b| a.difference <=> b.difference}

答案 6 :(得分:0)

添加DSM's Python version的Ruby版本。

假设:

> a=["0:1", "5:0", "3:3", "0:3", "1:3", "3:0", "1:0", "0:5", "5:5", "3:1"]

你可以这样做:

def rank(wl)
    w, l = wl.split(/:/).map(&:to_f)
    [w/(w+l > 0 ? -(w+l) : 0), -w, l]
    end
> a.sort { |a,b| rank(a)<=>rank(b) }
["5:0", "3:0", "1:0", "3:1", "5:5", "3:3", "1:3", "0:1", "0:3", "0:5"]

然后,如果你想以oo格式获得它,可能是这样的:

class Wl 
   def initialize(win_loss)
       @wl=win_loss
   end
   def wl()
      @wl
   end 
   def rank()
      w, l = @wl.split(/:/).map(&:to_f)
      [w/(w+l > 0 ? -(w+l) : 0), -w, l]
   end
   def to_s
       @wl
   end
   def inspect
       @wl 
   end 
   def <=>(other)
      rank <=> other.rank
   end 
end

> b=a.map{ |e| Wl.new(e) }
[0:1, 5:0, 3:3, 0:3, 1:3, 3:0, 1:0, 0:5, 5:5, 3:1]
> b.sort
[5:0, 3:0, 1:0, 3:1, 5:5, 3:3, 1:3, 0:1, 0:3, 0:5]