在Ruby中使用浮点数实现开放区间?

3

在 Ruby 中是否可以创建排除一个或两个端点的范围。因此,处理数学中开放和封闭区间边界的概念?

例如,我可以定义从 1.0 到 10.0 的范围,但不包括 1.0 吗?

假设(使用伪代码)

range = [1.0...10.0)

range === 1.0
=> false

range === 10.0
=> true
4个回答

7
在Ruby中,Range类只支持闭合和半开放(右开放)的范围。但是,你可以很容易地编写自己的范围类。
以下是Ruby中半开放范围的示例:
range = 1.0...10.0

range === 1.0
# => true

range === 10.0
# => false

Ruby 1.9兼容的Rubinius中,Range类的总行数为238行Ruby代码。如果您不需要您的开放范围类支持Ruby语言规范的所有细节、边角情况、特殊情况、怪癖、向后兼容怪癖等,则可以使用比238行少得多的代码。
如果您只需要测试是否包含,则应该使用以下代码:
class OpenRange
  attr_reader :first, :last

  def initialize(first, last, exclusion = {})
    exclusion = { first: false, last: false }.merge(exclusion)
    @first, @last, @first_exclusive, @last_exclusive = first, last, exclusion[:first], exclusion[:last]
  end

  def first_exclusive?; @first_exclusive end
  def last_exclusive?;  @last_exclusive  end

  def include?(other)
    case [first_exclusive?, last_exclusive?]
    when [true,  true]
      first <  other && other <  last
    when [true,  false]
      first <  other && other <= last
    when [false, true]
      first <= other && other <  last
    when [false, false]
      first <= other && other <= last
    end
  end

  alias_method :===, :include?

  def to_s
    "#{if first_exclusive? then '(' else '[' end}#@first...#@last#{if last_exclusive? then ')' else ']' end}"
  end

  alias_method :inspect, :to_s
end

起初,我试图使用嵌套的 if 来消除和最小化重复,但是那个方法实际上更加清晰明了,即使所有的单独比较都是重复的。DRY 是一条指导方针而不是口号。 - Jörg W Mittag

5

你可以使用 ... 来排除范围中的最右元素。请参考以下示例:

(1..10).to_a # an array of numbers from 1 to 10 - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

(1...10).to_a # an array of numbers from 1 to 9 - [1, 2, 3, 4, 5, 6, 7, 8, 9]

1
谢谢,-我将编辑我的问题以便更清晰。我正在使用浮点数工作。 - mattfitzgerald

4
使用..构建的范围从起始值到结束值都包含在内。而使用...创建的范围则不包括结束值。
('a'..'e').to_a    #=> ["a", "b", "c", "d", "e"]
('a'...'e').to_a   #=> ["a", "b", "c", "d"]

查看更多内容请点击这里

您可以很容易地编写自己的范围,以排除起始值。

对于浮点数范围:

(1.0..10.0).step.to_a # => [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
(1.0...10.0).step.to_a # => [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
(1.0..10.0).step(2.0).to_a # => [1.0, 3.0, 5.0, 7.0, 9.0]
(1.0...10.0).step(2.0).to_a # => [1.0, 3.0, 5.0, 7.0, 9.0]

再次道歉。我正在使用浮点数。编辑问题以反映这一点。range = (1.0...10.0); range === 1.0 => true - mattfitzgerald

0
几年后,但是...... 那么,利用一个case语句的事实如何?它按照出现顺序评估每个条件,并根据其第一个匹配项跟随路径。 在示例中,即使1.0在第二个“when”中是有效值,但它始终不执行任何操作。
case myvalue
    when 1.0
      #Don't do anything (or do something else)
    when 1.0...10.0
      #Do whatever you do when value is inside range 
      # not inclusive of either end point
    when 10.0
      #Do whatever when 10.0 or greater
    end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接