Iterate Over Ruby Time Object With Delta

Iterate over Ruby Time object with delta

Prior to 1.9, you could use Range#step:

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

However, this strategy is quite slow since it would call Time#succ 3600 times. Instead,
as pointed out by dolzenko in his answer, a more efficient solution is to use a simple loop:

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

If you're using Rails you can replace 3600 with 1.hour, which is significantly more readable.

Iterate over Time in ruby

If you are using Rails there is a Date method step: http://corelib.rubyonrails.org/classes/Date.html#M001273


On pure ruby just write simple loop:

t=Time.new(2012,01,01,0,0,0) #start time
max_time=Time.new(2012,01,31,23,59,59) #end time
step=60*60 #1hour
while t<=max_time
p t #your code here
t += step
end

To simplify use this ruby extension:

module TimeStep

def step(limit, step) # :yield: time
t = self
op = [:-,:<=,:>=][step<=>0]
while t.__send__(op, limit)
yield t
t += step
end
self
end
end

Time.send(:include, TimeStep) #include the extension

Usage:

t=Time.new(2012,01,01,0,0,0)
t.step(Time.new(2012,01,31,23,59,59),3600) do |time|
puts time
end

You can also down-iterate:

t=Time.new(2012,01,31)
t.step(Time.new(2012,01,1),-3600) do |time|
puts time
end

Iterate through dataframe to extract delta of a particular time period

Don't iterate through the dataframe. You can use a merge:

(df.merge(df.assign(Date=df['Date'] - pd.to_timedelta('6D')),
on='Date')
.assign(Value = lambda x: x['Value_y']-x['Value_x'])
[['Date','Value']]
)

Output:

        Date  Value
0 2020-10-09 30
1 2020-10-08 30
2 2020-10-07 30
3 2020-10-06 30
4 2020-10-05 30
5 2020-10-04 30
6 2020-10-03 30
7 2020-10-02 30
8 2020-10-01 30

How can I iterate over a reversed range with a specific step in Ruby?

Why don't you use Numeric#step:

From the docs:

Invokes block with the sequence of numbers starting at num, incremented by step (default 1) on each call. The loop finishes when the value to be passed to the block is greater than limit (if step is positive) or less than limit (if step is negative). If all the arguments are integers, the loop operates using an integer counter. If any of the arguments are floating point numbers, all are converted to floats, and the loop is executed floor(n + n*epsilon)+ 1 times, where n = (limit - num)/step. Otherwise, the loop starts at num, uses either the < or > operator to compare the counter against limit, and increments itself using the + operator.


irb(main):001:0> 10.step(0, -2) { |i| puts i }
10
8
6
4
2
0

Best way to iterate over a sequence and change one object at a time (Ruby)

Use Array#each:

self.answers.each {|a| a.some_attr = some_val if a.some_criteria}

Is it possible to iterate three arrays at the same time?

>> [1,2,3].zip(["a","b","c"], [:a,:b,:c]) { |x, y, z| p [x, y, z] }
[1, "a", :a]
[2, "b", :b]
[3, "c", :c]

transpose also works but, unlike zip, it creates a new array right away:

>> [[1,2,3], ["a","b","c"], [:a,:b,:c]].transpose.each { |x, y, z| p [x, y, z] }
[1, "a", :a]
[2, "b", :b]
[3, "c", :c]

Notes:

  • You don't need each with zip, it takes a block.

  • Functional expressions are also possible. For example, using map: sums = xs.zip(ys, zs).map { |x, y, z| x + y + z }.

  • For an arbitrary number of arrays you can do xss[0].zip(*xss[1..-1]) or simply xss.transpose.

Iterating between two DateTimes, with a one hour step

Similar to my answer in "How do I return an array of days and hours from a range?", the trick is to use to_i to work with seconds since the epoch:

('2013-01-01'.to_datetime.to_i .. '2013-02-01'.to_datetime.to_i).step(1.hour) do |date|
puts Time.at(date)
end

Note that Time.at() converts using your local time zone, so you may want to specify UTC by using Time.at(date).utc

How can i loop through a daterange with different intervals?

Loop until the from date plus 1.day, 1.week, or 1.month is greater than the to date?

 > from = Time.now
=> 2012-05-12 09:21:24 -0400
> to = Time.now + 1.month + 2.week + 3.day
=> 2012-06-29 09:21:34 -0400
> tmp = from
=> 2012-05-12 09:21:24 -0400
> begin
?> tmp += 1.week
?> puts tmp
?> end while tmp <= to
2012-05-19 09:21:24 -0400
2012-05-26 09:21:24 -0400
2012-06-02 09:21:24 -0400
2012-06-09 09:21:24 -0400
2012-06-16 09:21:24 -0400
2012-06-23 09:21:24 -0400
2012-06-30 09:21:24 -0400
=> nil

Get the count of elements in a ruby range made of Time objects

There's no such method as Range#size, try Range#count (as suggested by Andrew Marshall), though it still won't work for a range of Time objects.

If you want to perform number-of-days computations, you're better off using Date objects, either by instantiating them directly (Date.today - 31, for example), or by calling #to_date on your Time objects.

Date objects can be used for iteration too:

((Date.today - 2)..(Date.today)).to_a
=> [#<Date: 2012-06-17 ((2456096j,0s,0n),+0s,2299161j)>,
#<Date: 2012-06-18 ((2456097j,0s,0n),+0s,2299161j)>,
#<Date: 2012-06-19 ((2456098j,0s,0n),+0s,2299161j)>]

((Date.today - 2)..(Date.today)).map(&:to_s)
=> ["2012-06-17", "2012-06-18", "2012-06-19"]

Iterate over a specific directory level

Have you tried it without the **/ (include sub-directories)? The / at the end takes only folders, not files.

Dir['../../SOURCE/SOURCE_*/*/'].each do |dir|
...
end


Related Topics



Leave a reply



Submit