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其视为 false 值,这允许使用不同的语法进行复杂的比较:

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

我发现通过操作符进行的直通0操作||简单易读且优雅。我喜欢使用||的一件事是,一旦比较有值,计算就会短路。

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

4

2 回答 2

7

除了sawa的回答,结果也能应该就地评估,以便返回 -1、0 或 +1:

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

这是因为Array#<=>

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

实施后,您可以<=>免费Comparable获取、、、、、和。<<===>=>between?

于 2013-08-29T08:53:59.880 回答
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
于 2013-08-29T08:44:12.180 回答