3

如何对范围数组进行排序

ranges = [Range.new(0, 3, true), Range.new(3, 5, true), Range.new(5, 7, true), Range.new(7, 9, true), Range.new(9, 11, true), Range.new(11, 100, true)]
ranges.sort
=> ArgumentError: comparison of Range with Range failed
from (irb):7:in `sort'
from (irb):7
from /Users/praveena/.rvm/rubies/ruby-2.0.0-p247/bin/irb:16:in `<main>'

但是当我尝试

2.0.0p247 :022 > (3...4) <=> (4...8)
=> nil
2.0.0p247 :023 > (3...4) <=> (1...2)
=> nil

我错过了什么吗?

4

2 回答 2

2

nil是来自用于排序的比较操作的不可用值。

如果您<=>在两个Comparable对象之间尝试,a <=> b它们将始终分别返回 -1、0 或 1,分别表示“a 小于 b”、“a 等于 b”和“a 大于 b”。

因此,要对Range对象进行排序,您需要覆盖<=>并定义自己应该按什么顺序排序。请注意,这必须是您为了对它们进行排序而编造的东西,Range对象没有固有的或有意义的排序顺序。

例如,我可以决定范围按 a 的开始顺序排序,如果它们相等则Range回退到 the 的末尾:Range

class Range
  def <=>(other)
    [min, max] <=> [other.min, other.max]
  end
end

[(1..3),(1...3),(4..5),(2..3)].sort
 => [1...3, 1..3, 2..3, 4..5]
于 2013-08-28T21:56:08.600 回答
2

似乎 range 有一个实现<=>,但并不完整。让我们检查:

> Range.new(3,4) <=> Range.new(3,4)
=> 0
# It seems that it correctly identify when the two are equals

> Range.new(3,4) <=> Range.new(4,4)
=> nil
# But it seems that it fails to fail when both are different!

定义这个方法是Range因为它实际上是Object上定义的(!!!),因此每个对象都定义了这个方法,这并不意味着它可以工作。实际上范围的实现是默认的。让我们检查一下:

# lets define a dummy class
class A
end
=> nil

# and create an object
a = A.new
=> #<A:0x9b1d998>

# can correctly identify when equal
a <=> a
=> 0

# but invalid answer when not equal!
a <=> 1
=> nil

此时,您现在应该了解代码中发生了什么。

范围没有规范<=>方法是完全可以理解的,因为没有更大范围的数学定义(我知道),也没有常识定义。

于 2013-08-28T22:02:30.473 回答