Count time within time range - ruby-on-rails

I need to count amount of time in specified range. For example, I have range (let's call it peak hours) 12:00-14:00. And i have another range(visit time), that might change, for ex 9:00-15:00. How do I get intersected hours for these 2 ranges?
As result I would like to get something like: {peak_hours: 2, regular_hours: 4}
Here peak_hours value is 2 as that many peak hours overlap with regular hours. And, regular_hours value is 4 as that many regular hours do not overlap with peak hours.
I'm kinda stuck with solution. I tried to use time ranges, but that didn't work for me. This is the code
peak_hours_range = Time.parse(peak_hour_start)..Time.parse(peak_hour_end)
session_range = visit_start..visit_end
inters = session_range.to_a & peak_hours_range.to_a
But this throws me type error

Here is one way to do it, we find the total hours in both ranges included, and then remove the peak hours from it to get effective regular hours.
require "time"
peak_hour_start = "12:00"
peak_hour_end = "14:00"
regular_hour_start = "9:00"
regular_hour_end = "15:00"
ph = (Time.parse(peak_hour_start).hour...Time.parse(peak_hour_end).hour).to_a
#=> [12, 13]
rh = (Time.parse(regular_hour_start).hour...Time.parse(regular_hour_end).hour).to_a
#=> [9, 10, 11, 12, 13, 14]
total = (ph + rh).uniq
#=> [12, 13, 9, 10, 11, 14]
r = {peak_hours: (ph - rh).size, regular_hours: (total - ph).size}
#=> {:peak_hours=>2, :regular_hours=>4}

You can always try to find the intersection yourself.
inters = nil
intersection_min = [peak_hour_start, visit_start].max
intersection_max = [peak_hour_end, visit_end].min
if intersection_min < intersection_max
inters = [intersection_min, intersection_max]
end
inters
Of course this can be cleaned up by extracting it out into it's own method.

Related

Swift - Sort array element by range

I'm currently working with the "Charts" pod.
My app shows a bar chart of athletes results, with:
X Axis: number of reps / time / rounds / weight
Y Axis: number of athletes
I would like to gather the number of reps in different groups.
Something that would be like: 10 < x < 20, 20 < x < 30, etc...
Rather than the real total of reps.
Something like that:
What would be the best way to do so? I though about some approaches:
Round the number of reps to transform 19 and 15 to 10 and 10 for example (for the 10 < x < 20 category)
The problem with that method is that I don't know if I can do the same for the "time (seconds)
Create a new array with dictionnaries inside, something like:
[["10-20": 15, 17, 19], ["20-30": 21, 22, 22, 24], etc..]
But I don't know how to achieve that...
What would be the best way?
You can use Dictionary's init(grouping:by:) initializer to create such a dictionary:
let array = [15,17,19,22,24,24,27]
let dict = Dictionary(grouping: array, by: { $0 / 10 })
// dict is [2: [22, 24, 24, 27], 1: [15, 17, 19]]
If I understood you correctly, you probably have a bunch of Athletes and they have a reps property. You can group by $0.reps / 10 instead:
Dictionary(grouping: athletes, by: { $0.reps / 10 })
And then map the keys and values to this:
.map { ("\($0.key * 10) - \(($0.key + 1) * 10)", $0.value.count) }
// now you have this:
// [("20 - 30", 4), ("10 - 20", 3)]

ipairs loop always returning just one of the values in lua?

Quick edit: _G.i is the 1 - 24 table I set to create a 24 hour time frame. It's globally stored in a tertiary script and implemented like this:
_G.i = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}
So I'm trying to get this loop to work with a day/night cycle I have created. I want the loop to constantly check what time it is and print that time to the console based on a few parameters I set.
light = script.Parent.lightPart.lightCone
timeofday = ""
wait(1)
function checkTime()
for i, v in ipairs(_G.i) do
wait(1)
print(v)
print(timeofday)
if v > 20 and v < 6 then
timeofday = "night"
else
timeofday = "day"
end
end
end
while true do
checkTime()
wait(1)
end
For some reason, this is only printing day in the console even though I have it looping properly. The times are matched with the same of those in the day-night script. I'll post that here as well.
function changeTime()
for i, v in ipairs(_G.i) do
game.Lighting:SetMinutesAfterMidnight(v * 60)
wait(1)
end
end
while true do
changeTime()
end
Sorry if this post is sloppy or the code is sloppy I'm new to both. Have been trying to figure this out on my own, and been doing good on it originally I had no clue what a ipairs loops was but I managed to get it working with the day night cycle instead of a infinite wait(1) loop.
Your issue is the line:
if v > 20 and v < 6 then
v can never be both greater than 20 and less than 6. You need the or logical operator.
Beyond that, I'm not sure why you are using the global i to hold a list of the numbers 1 through 24? You can achieve the same affect with a ranging for loop. Also, if you are trying to check the current time set by your lower code, then you should store the time value in a global variable. Like so:
light = script.Parent.lightPart.lightCone
current_time = 0
function checkTime()
print(current_time)
if current_time > 20 or current_time < 6 then
timeofday = "night"
else
timeofday = "day"
end
print(timeofday)
end
while true do
checkTime()
wait(0.1)
end
function changeTime()
for v = 1, 24 do
game.Lighting:SetMinutesAfterMidnight(v * 60)
current_time = v
end
end
while true do
changeTime()
wait(1)
end
The issue with the way you were doing it is that you assume that the checkTime() function will always run after the changeTime() function, which is not necessarily the case.

Domoticz lua motion sensor

--this script will turn of the light at the second living room when there is x min no movement detected on the Motion Sensor.
--The script does run and it sometime works, like once or twice a day. but it has to work always, I can't figure out why it is not working.
t1 = os.time()
s = otherdevices_lastupdate['Motion']
year = string.sub(s, 1, 4)
month = string.sub(s, 6, 7)
day = string.sub(s, 9, 10)
hour = string.sub(s, 12, 13)
minutes = string.sub(s, 15, 16)
seconds = string.sub(s, 18, 19)
commandArray = {}
t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds}
difference = (os.difftime (t1, t2))
print(difference)
if (otherdevices['Motion'] == 'On' and difference > 60 and difference < 200) then
commandArray['Light']= 'Off'
print('2 minutes no movement, turn off Light 2th Living Room')
end
return commandArray
If the script runs successfully but it doesn't turn the light off even if it's expected to do so, then there are not many possible reasons.
Either otherdevices['Motion'] is not 'On' (the check is case sensitive) or the difference is out of the expected range of 60..200 seconds.
Solution #1:
...
if (otherdevices['Light']=='On' and otherdevices['Motion']~='On' and difference > 120) then
CommandArray['Light']='Off'
}
Solution #2 (better):
configure the Motion device so it activates the Light for 120 seconds, so it will be turned off automatically when Motion sensor stops toggling.

Find successive maximum differences in array

I have created an application in which the user continually rotates the phone about the z-axis (yaw) with the screen of the phone facing upwards. I would like to generate the angle between the two extremes each time the rotation changes direction.
Imagine an array of the following values: [-5,-3,-2, 0, 1, 2, 6, 5, 3, 2,-1,-3,-4,-7,-4,-3,...]. What I would like to do is find the relative maximums and minimums of the array in order to find the differences from one relative minimum to the next relative maximum. In the given array, -5 would be the first relative minimum and then 6 would be the next relative maximum. The difference here would be 11 units. From that relative maximum of 6, the next relative minimum is -7. The difference here would be 13 units. The process would continue on until the end of the array. I would like these difference values to be entered into an array of their own, i.e. [11,13,...]. Would greatly appreciate any assistance!
The way I see this your first value in the array is always your initial relative minimum AND maximum since you have absolutely no basis of comparison from the get-go (unless you prime both relMin and relMax to 0 OR define a range to find your relMin and relMax). With that in mind the logic behind your example itself is flawed given your assumption of using -5 & 6 as the first comparison pair.
Let's use your array and iterate through the array with a For Loop...
[-5,-3,-2, 0, 1, 2, 6, 5, 3, 2,-1,-3,-4,-7,-4,-3,...]
0: relMin = -5, relMax = -5, delta = 0
1: relMin = -5, relMax = -3, delta = 2
2: relMin = -5, relMax = -2, delta = 3
3: relMin = -5, relMax = 0, delta = 5
4: relMin = -5, relMax = 1, delta = 6
5: relMin = -5, relMax = 2, delta = 2
6: relMin = -5, relMax = 6, delta = 11
7:
....
13: relMin = -7, relMax = 6, delta = 13
....
Essentially what you're doing is writing to your output array any time your current delta is not equal to your previous delta. Since a change between relMin and relMax is mutually exclusive (only one of those values can change as you traverse the array) all you have to check for is inequality...
//prime your values
//if it make sense for your purposes prime them both with 0
//this also assumes you have at least 1 value in valueArray
relMin = valueArray[0];
relMax = valueArray[0];
//the following line will always be true if you use valueArray[0] as your relMin and relMax baseline
deltaArray[0] = 0;
for (i = 0; i < [valueArray count]; i++)
{
if (valueArray[i] < relMin)
{
relMin = valueArray[i];
}
if (valueArray[i] > relMax)
{
relMax = valueArray[i];
}
deltaPrevious = deltaArray[[deltaArray count] - 1];
deltaCurrent = relMax - relMin;
if (deltaCurrent != deltaPrevious)
{
deltaArray[deltaArray count] = deltaCurrent;
}
}
My approach to this problem would be to first write an algorithm that detects the indices of the maximums and minimums, and then finds differences from there.
To get the maxes and mins, I would recommend iterating through the array and looking at the difference between the current and the previous and next value. You need to looking at changes in sign of the differences:
A minimum will occur when the differences change from negative to positive, and a maximum will occur when the differences change from positive to negative.
For example, look at this part of your array: [1,2,6,5,3]. The difference from 1 to 2 is positive, from 2 to 6 is positive, but from 6 to 5 is negative. The sign of the differences changed from positive to negative at the 6, so we know it is a maximum.
Note that you also need to include the first and last elements as possible maxes or mins.
Once you get the indices of maximums and minimums, you should be able to get their differences fairly easily.
In a most basic sense, you could iterate through the array, checking to see if the next value is greater than or less than the previous value. Whenever you reach a change (was increasing, now decreasing, or vice versa) you have found a relative max/min (respectively). A for loop to iterate, a boolean flag to check against (whether you were increasing or decreasing) and the obvious knowledge of both your current and previous index in the array to check/store.
I don't quite feel comfortable giving exact code for this since it's very basic and seems very much like a homework question...

Subtract dates in Ruby and get the difference in minutes

how do i subtract two different UTC dates in Ruby and then get the difference in minutes?
Thanks
If you subtract two Date or DateTime objects, the result is a Rational representing the number of days between them. What you need is:
a = Date.new(2009, 10, 13) - Date.new(2009, 10, 11)
(a * 24 * 60).to_i # 2880 minutes
or
a = DateTime.new(2009, 10, 13, 12, 0, 0) - DateTime.new(2009, 10, 11, 0, 0, 0)
(a * 24 * 60).to_i # 3600 minutes
(time1 - time2) / 60
If the time objects are string, Time.parse(time) them first
https://rubygems.org/gems/time_difference - Time Difference gem for Ruby
start_time = Time.new(2013,1)
end_time = Time.new(2014,1)
TimeDifference.between(start_time, end_time).in_minutes
Let's say you have two dates task_signed_in and task_signed_out for a simple #user object. We could do like this:
(#user.task_signed_out.to_datetime - #user.task_signed_in.to_datetime).to_i
This will give you result in days. Multiply by 24 you will get result in hours and again multiply by 60 you will result in minutes and so on.
This is the most up to date solution tested in ruby 2.3.x and above.

Resources