Итерация по объекту Ruby Time с дельтой - PullRequest
31 голосов
/ 01 февраля 2009

Есть ли способ перебрать временной диапазон в Ruby и установить дельту?

Вот идея того, что я хотел бы сделать:

for hour in (start_time..end_time, hour)
    hour #=> Time object set to hour
end

Вы можете перебирать объекты Time, но они возвращаются каждую секунду между ними. Что мне действительно нужно, так это способ установить смещение или дельту (например, минуты, часы и т. Д.)

Это встроено в Ruby или есть приличный плагин?

Ответы [ 3 ]

55 голосов
/ 01 февраля 2009

До 1.9 вы могли использовать Range#step:

(start_time..end_time).step(3600) do |hour|
  # ...
end

Однако эта стратегия довольно медленная, так как она будет вызывать Time#succ 3600 раз. Вместо, как отметил Долзенко в своем ответе , более эффективным решением является использование простого цикла:

hour = start_time
while hour < end_time
  # ...
  hour += 3600
end

Если вы используете Rails, вы можете заменить 3600 на 1.hour, что значительно удобнее для чтения.

39 голосов
/ 27 августа 2009

Если ваши start_time и end_time на самом деле являются экземплярами класса Time, то решение с использованием Range#step будет крайне неэффективным, поскольку оно будет повторяться каждую секунду в этом диапазоне с Time#succ. Если вы конвертируете свои времена в целые числа, будет использовано простое сложение, но в результате вы получите что-то вроде:

(start_time.to_i..end_time.to_i).step(3600) do |hour|
  hour = Time.at(hour)     
  # ...
end

Но это также можно сделать с помощью более простого и эффективного цикла (т. Е. Без всех преобразований типов):

hour = start_time
begin
  # ...      
end while (hour += 3600) < end_time
17 голосов
/ 30 декабря 2009

Range # step метод очень медленный в этом случае. Используйте begin..end while, поскольку долзенко разместил здесь.

Вы можете определить новый метод:

  def time_iterate(start_time, end_time, step, &block)
    begin
      yield(start_time)
    end while (start_time += step) <= end_time
  end

тогда

start_time = Time.parse("2010/1/1")
end_time = Time.parse("2010/1/31")
time_iterate(start_time, end_time, 1.hour) do |t|
  puts t
end

если в рельсах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...