对一系列范围进行排序

时间:2013-08-28 21:42:42

标签: ruby sorting range

如何对范围数组进行排序

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

我错过了什么吗?

2 个答案:

答案 0 :(得分:2)

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

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

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

例如,我可以决定范围按照Range的开头顺序排序,如果它们相等则会回落到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]

答案 1 :(得分:2)

似乎范围有<=>的实现,但不完整。让我们检查:

> 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中定义,因为它实际上是on the Object class(!!!)定义的,因此每个对象都定义了此方法,这并不意味着它可以工作。实际上,范围的实现是默认的。让我们检查一下:

# 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

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

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