考虑一个类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都很满意)
答案 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]