Объявление целого диапазона с шагом!= 1 в Ruby

ОБНОВЛЕНИЕ 2: для потомков именно так я решил это сделать (благодаря вводу Jorg):

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

(Очевидно, что есть много способов сделать это, но похоже, что это самый "рубиновый" способ сделать это, и это именно то, что я был после.)


UPDATE: ОК, поэтому я искал step:

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

Но, оказывается, я не был на 100% в своем первоначальном вопросе. Я на самом деле хочу перебрать этот диапазон назад. К моему удивлению, негативный шаг не является законным.

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

Итак: как это сделать назад?


Эй, ребята, я совершенно новый для Ruby, поэтому будьте осторожны.

Скажем, я хочу перебирать диапазон четных чисел от 2 до 100; как бы я это сделал?

Очевидно, я мог бы сделать:

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

Но, очевидно (опять же), это было бы довольно глупо.

Я знаю, что могу сделать что-то вроде:

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

Я считаю, что могу написать собственный собственный класс, который предоставляет свой собственный метод each (?). Я почти уверен, что это было бы излишним.

Меня интересуют две вещи:

  • Возможно ли это с некоторым изменением стандартного синтаксиса Range (т.е. (x..y).each)?
  • В любом случае, какой был бы самый идиоматический "способ Ruby" для достижения этого (используя Range или иначе)? Как я уже сказал, я новичок в языке; так что любое руководство, которое вы можете предложить о том, как делать вещи в более типичном стиле Ruby, будет высоко оценено.

Ответ 1

Вы не можете объявить Range с шагом. Диапазоны не имеют шагов, у них просто есть начало и конец.

Вы можете, конечно, выполнить итерацию по шагу Range, например, следующим образом:

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

Но если все, что вам нужно, это повторить, то для чего вам нужно Range в первую очередь? Почему бы просто не повторить?

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

Это имеет дополнительное преимущество, в отличие от reverse_each ему не нужно создавать промежуточный массив.

Ответ 3

У меня была аналогичная проблема, вот несколько способов, которые я нашел, чтобы сделать то же самое, что я использовал шаг в конце, потому что он допускал NEGATIVE и FRACTIONAL приращения, и у меня не было никаких условий, кроме границ поиска

  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