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 simplyxss.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
Why Are Methods in Ruby Documentation Preceded by a Hash Sign
Getaddrinfo: Nodename Nor Servname Provided, or Not Known
What Are the Magic $-Prefixed Variables in Ruby
Ruby: What Does the Comment "Frozen_String_Literal: True" Do
How to Compile and Statically Link Ruby Libs for Docker
Installing Rvm (Ruby Version Manager)
Calculating the Number of Weeks in a Year with Ruby
How to Find a Hash Key Containing a Matching Value
Uninstalling All Gems Ruby 2.0.0
When to Use Each Method of Launching a Subprocess in Ruby
Why Isn't Self Always Needed in Ruby/Rails/Activerecord
How to Install MySQL2 Gem on Windows 7
Getting "Warning! Path Is Not Properly Set Up" When Doing Rvm Use 2.0.0 --Default
Can't Install Rails on MAC Os Catalina