Ruby中的反向`...`方法

3
有没有一个类似于(1...4).to_a的标准方法在Ruby中,除了反向之外,即 (4...1).to_a 将是[4,3,2,1]
我意识到可以通过(1...4).to_a.reverse来轻松定义它,但这让我感到奇怪,因为 1)我是否遗漏了什么? 2)如果没有,那么它为什么不是一个功能性/实用性的方法呢?
3个回答

9
最简单的方法可能是这样的:
4.downto(1).to_a #=> [4, 3, 2, 1]

或者您可以使用step

4.step(1,-1).to_a #=> [4, 3, 2, 1]

最后,有一个相对不常见的有趣解决方案:

(-4..-1).map(&:abs) #=> [4, 3, 2, 1]

8

(1...4)是一个范围。在Ruby中,范围不像数组;它们的优势之一是可以创建如下范围:

(1..1e9)

不占用计算机所有的内存。此外,您可以创建此范围:
r = (1.0...4.0)

这意味着“所有浮点数的集合从1.0到4.0,包括1.0但不包括4.0”。

换句话说:

irb(main):013:0> r.include? 3.9999
=> true
irb(main):014:0> r.include? 3.99999999999
=> true
irb(main):015:0> r.include? 4.0
=> false

您可以将整数范围转换为数组:

irb(main):022:0> (1..4).to_a
=> [1, 2, 3, 4]

但不是浮点数范围:

irb(main):023:0> (1.0...4.0).to_a
TypeError: can't iterate from Float
        from (irb):23:in `each'
        from (irb):23:in `to_a'
        from (irb):23
        from /home/mslade/rubygems1.9/bin/irb:12:in `<main>'

由于没有自然的方法可以迭代浮点数。因此,您需要使用#step
irb(main):015:0> (1..4).step(0.5).to_a
=> [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0]
irb(main):016:0> (1...4).step(0.5).to_a
=> [1.0, 1.5, 2.0, 2.5, 3.0, 3.5]

如果您需要反向迭代一个大整数范围,请使用 Integer#downto

('1.0'...'4.0').to_a.map(&:to_f)怎么样? - Grzegorz Łuszczek
这是一个不错的技巧,但它只适用于10^N。如果你想要以0.05的步长呢? - Michael Slade
('0.00'..'10.00').step(5).to_a.map(&:to_f) 或者去掉 to_a.map 并得到字符串的枚举器。 - Grzegorz Łuszczek

1
你可以通过以下方式自动修补Range#to_a以使其与reverse一起工作:
class Range

  alias :to_a_original :to_a

  def reverse
    Range.new(last, first)
  end

  def to_a
    (first < last) ? to_a_original : reverse.to_a_original.reverse
  end

end

结果:

(4..1).to_a
=> [4, 3, 2, 1]

这种方法被称为“重新打开”类,也叫“猴子补丁”。一些开发者喜欢这种方法,因为它能添加有用的功能,而另一些人则不喜欢它,因为它会干扰 Ruby 核心。

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