Declaring an integer Range with step != 1 in Ruby

2019-01-25 06:12发布

问题:

UPDATE 2: For posterity, this is how I've settled on doing it (thanks to Jorg's input):

100.step(2, -2) do |x|
    # my code
end

(Obviously there are plenty of ways to do this; but it sounds like this is the most "Ruby" way to do it; and that's exactly what I was after.)


UPDATE: OK, so what I was looking for was step:

(2..100).step(2) do |x|
    # my code
end

But it turns out that I wasn't 100% forthcoming in my original question. I actually want to iterate over this range backwards. To my surprise, a negative step isn't legal.

(100..2).step(-2) do |x|
    # ArgumentError: step can't be negative
end

So: how do I do this backwards?


Hey guys, I'm completely new to Ruby, so be gentle.

Say I want to iterate over the range of even numbers from 2 to 100; how would I do that?

Obviously I could do:

(2..100).each do |x|
    if x % 2 == 0
        # my code
    end
end

But, obviously (again), that would be pretty stupid.

I know I could do something like:

i = 2
while i <= 100
    # my code
    i += 2
end

I believe I could also write my own custom class that provides its own each method (?). I am almost sure that would be overkill, though.

I'm interested in two things:

  1. Is it possible to do this with some variation of the standard Range syntax (i.e., (x..y).each)?
  2. Either way, what would be the most idiomatic "Ruby way" of accomplishing this (using a Range or otherwise)? Like I said, I'm new to the language; so any guidance you can offer on how to do things in a more typical Ruby style would be much appreciated.

回答1:

You can't declare a Range with a "step". Ranges don't have steps, they simply have a beginning and an end.

You can certainly iterate over a Range in steps, for example like this:

(2..100).step(2).reverse_each(&method(:p))

But if all you want is to iterate, then what do you need the Range for in the first place? Why not just iterate?

100.step(2, -2, &method(:p))

This has the added benefit that unlike reverse_each it does not need to generate an intermediate array.



回答2:

This question answers yours: about ruby range?

(2..100).step(2) do |x|
    # your code
end


回答3:

I had similar issue here are the various ways I found to do the same SIMPLE thing I used step in the end because it allowed for NEGATIVE and FRACTIONAL increments and I had no conditions, other than the bounds to look for

  case loop_type

    when FOR
      # doen't appear to have a negative or larger than 1 step size!
      for kg in 50..120 do
        kg_to_stones_lbs(kg)
      end

    when STEP
      120.step(70,-0.5){ |kg|
        kg_to_stones_lbs(kg)
      }

    when UPTO
      50.upto(120) { |kg|
        kg_to_stones_lbs(kg)
      }

    when DOWNTO
      120.downto(50){ |kg|
        kg_to_stones_lbs(kg)
      }

    when RANGE
      (50..120).reverse_each{ |kg|
        kg_to_stones_lbs(kg)
      }

    when WHILE
      kg = 120
      while kg >= 50
        kg_to_stones_lbs(kg)
        kg -= 0.5
      end
  end

O/P:

92.0kg - 14st 7lbs

91.5kg - 14st 6lbs

91.0kg - 14st 5lbs

90.5kg - 14st 4lbs

90.0kg - 14st 2lbs

89.5kg - 14st 1lbs

89.0kg - 14st 0lbs

88.5kg - 13st 13lbs

88.0kg - 13st 12lbs



标签: ruby range