2013-08-29 102 views
5

对于“小于”,“等于”和“大于”,<=>方法应该分别返回-101。对于某些类型的可排序对象,基于多个属性的排序顺序是正常的。下面的作品,但我认为它看起来笨拙:复杂的比较有一个漂亮的语法吗?

class LeagueStats 
    attr_accessor :points, :goal_diff 
    def initialize pts, gd 
    @points = pts 
    @goal_diff = gd 
    end 
    def <=> other 
    compare_pts = points <=> other.points 
    return compare_pts unless compare_pts == 0 
    goal_diff <=> other.goal_diff 
    end 
end 

尝一尝:

[ 
    LeagueStats.new(10, 7), 
    LeagueStats.new(10, 5), 
    LeagueStats.new(9, 6) 
].sort 
# => [ 
#  #<LS @points=9, @goal_diff=6>, 
#  #<LS @points=10, @goal_diff=5>, 
#  #<LS @points=10, @goal_diff=7> 
# ] 

Perl将0为假值,允许不同的语法复杂的比较:

{ 
    return ($self->points <=> $other->points) || 
     ($self->goal_diff <=> $other->goal_diff); 
} 

我发现0通过||操作符易于阅读和优雅翻倒。我喜欢使用||的一件事是一旦比较结果有一个值,计算的短路。

我在Ruby中找不到类似的东西。有没有更好的方法来构建相同的比较复合体(或其他任何选择第一个非零项),理想情况下无需事先计算所有值?

回答

7

除了泽穗希的答案,结果应就地进行评估,以返回-1 ,0或+1:

class LeagueStats 
    def <=> other 
    [points, goal_diff] <=> [other.points, other.goal_diff] 
    end 
end 

This works becau Array#<=>

以“元素明智”的方式比较数组;前两个 元素不相等将决定整个比较的返回值。

实施<=>后,您可以包括Comparable并获得<<===>=>between?是免费的。

3

可以使用Enumerable#sort_by代替sort

[LeagueStats.new(10,7),LeagueStats.new(10,5),LeagueStats.new(9,6)].sort_by { |ls| 
    [ls.points, ls.goal_diff] 
} 
# => [#<LeagueStats:0x00000001a806c8 @points=9, @goal_diff=6>, 
#  #<LeagueStats:0x00000001a806f0 @points=10, @goal_diff=5>, 
#  #<LeagueStats:0x00000001a80718 @points=10, @goal_diff=7>] 

class LeagueStats 
    ... 

    def to_a 
    [points, goal_diff] 
    end 

    def <=> other 
    to_a <=> other.to_a 
    end 
end 
+0

这很酷,但我希望LeagueStats有一个固有的排序顺序,这是他们的目的。 –

+0

@NeilSlater,好的,我添加了另一个源自sawa答案的代码。 – falsetru