有没有理由我们不能在ruby中反复"反向范围"?

fif*_*uri 98 ruby iteration range

我尝试使用Range并向后迭代each:

(4..0).each do |i|
  puts i
end
==> 4..0
Run Code Online (Sandbox Code Playgroud)

迭代通过0..4写入数字.在另一个范围r = 4..0似乎没问题r.first == 4,r.last == 0.

我觉得上面的结构不能产生预期的结果似乎很奇怪.这是什么原因?这种行为合理的情况是什么?

Joh*_*lla 93

范围就是:由开始和结束定义的东西,而不是其内容.在一般情况下,在一个范围内"迭代"并不真正有意义.例如,考虑如何"迭代"两个日期产生的范围.你会白天迭代吗?按月?一年?一周?它没有明确定义.IMO,它允许前进范围的事实应该被视为一种便利方法.

如果你想在这样的范围内向后迭代,你总是可以使用downto:

$ r = 10..6
=> 10..6

$ (r.first).downto(r.last).each { |i| puts i }
10
9
8
7
6
Run Code Online (Sandbox Code Playgroud)

以下是来自其他人的更多想法,为什么很难同时允许迭代并始终​​处理反向范围.

  • 我认为直观地迭代1到100或100到1的范围意味着使用步骤1.如果有人想要不同的步骤,则更改默认值.同样,对于我(至少)从1月1日到8月16日的迭代意味着踩了几天.我认为通常我们可以达成一致意见,因为我们直觉上就是这样.感谢您的回答,您提供的链接也很有用. (8认同)
  • `.each`有冗余,`5.downto(1){| n | 把n}做得很好.而且,而不是所有r.first r.last的东西,只做`(6..10).reverse_each`. (8认同)
  • 我仍然认为为许多范围定义"直观"迭代很难做到一致,而且我不同意迭代日期以直觉方式暗示等于1天的步骤 - 毕竟,一天本身已经是一个范围时间(从午夜到午夜).例如,谁说"1月1日至8月18日"(恰好是20周)并不意味着需要几周而不是几天的迭代?为什么不按小时,分钟或秒进行迭代? (3认同)

小智 90

如何(0..1).reverse_each向后迭代范围?


Jon*_*röm 18

迭代Ruby中的一个范围,each调用该范围中succ第一个对象的方法.

$ 4.succ
=> 5
Run Code Online (Sandbox Code Playgroud)

并且5超出范围.

您可以使用此hack模拟反向迭代:

(-4..0).each { |n| puts n.abs }
Run Code Online (Sandbox Code Playgroud)

约翰指出,如果它跨越0,这将不起作用.这将:

>> (-2..2).each { |n| puts -n }
2
1
0
-1
-2
=> -2..2
Run Code Online (Sandbox Code Playgroud)

不能说我真的喜欢他们中的任何一个,因为他们有点模糊了意图.

  • 聪明的黑客!但是,它不适用于跨越0的范围. (3认同)
  • 不,但乘以-1而不是使用.abs你可以. (2认同)

bta*_*bta 12

根据"Programming Ruby"一书,Range对象存储范围的两个端点,并使用该.succ成员生成中间值.根据您在您的范围内使用的数据类型,您始终可以创建一个子类Integer并重新定义该.succ成员,使其像反向迭代器一样(您可能也想要重新定义.next).

您还可以在不使用范围的情况下获得所需的结果.试试这个:

4.step(0, -1) do |i|
    puts i
end
Run Code Online (Sandbox Code Playgroud)

这将以步长-1从步进4到0.但是,我不知道这是否适用于除Integer参数之外的任何内容.


Ser*_*nin 11

另一种方式是 (1..10).to_a.reverse


小智 6

您甚至可以使用for循环:

for n in 4.downto(0) do
  print n
end
Run Code Online (Sandbox Code Playgroud)

打印:

4
3
2
1
0
Run Code Online (Sandbox Code Playgroud)