I am looking for ways to convert a Duration (#sys.duration) system entity from Dialogflow in JavaScript code from minutes to seconds.
I ask the user for a certain duration, where the user can answer, e.g.:
20 minutes
5 minutes
etc.
that input is saved into a variable the_duration. Now to do certain calculations, I need to convert this into seconds. How can I achieve this?
EDIT: Perhaps it would help if I need to extract the number from the string? I've tried looking for this way, but provided examples don't really apply for this specific case with minutes.
The #sys.duration system entity will send you an Object with two attributes, "amount" which contains an integer, and "unit" which contains a string.
So in Javascript, this would be represented something like:
{
"amount": 20,
"unit": "min"
}
To convert this to seconds, you would lookup how many seconds are in the "unit" provided and multiply it by the amount.
A good way to do this lookup would be to create an object that has, as attributes, the possible unit names and as values the number of seconds. This works well for most units up to a week. When you hit a month or a year (or longer), however, you run into trouble since the number of seconds for these periods can be variable. To represent these, I'll mark these as a negative number, so you can check if the conversion failed. (I'm ignoring issues with clock changes such as due to Daylight Saving Time / Summer Time.)
I haven't fully tested this code, but it appears to be correct. This function lets you pass the object sent in the the_duration parameter and will return the number of seconds:
function durationToSeconds( duration ){
const mult = {
"s": 1,
"min": 60,
"h": 60*60,
"day": 60*60*24,
"wk": 60*60*24*7,
"mo": -1,
"yr": -1,
"decade": -1
};
return duration.amount * mult[duration.unit];
}
Extracting the number from the string is certainly possible, and you can adapt this function to work that way, but since Dialogflow already gives it to you as an object with normalized strings, it would be significantly more difficult.
Related
Say you have an array of objects representing events over time, i.e.:
[
{
offset: 1,
event_value: 22
},
{
offset: 2,
event_value: 19
},
...etc
]
where offset refers to the number of minutes that have passed since the start of the event.
There is no guarantee the offsets will be in a predictable interval, i.e. we can have an offset at the 1 minute mark, 2, 3, 5, 8, etc.
If you wanted to find best the 20-minute period with the highest average event_value, what would be the best approach to solving this?
(Bear in mind the data is continuous, such as stock prices over time.)
One approach I considered is to loop through the events (from the first one up until the one 20 minutes from the end), calculate the offset 20 minutes on from that point, and see if there is an event there. If there is, calculate the average for that period.
If there isn't an event at that offset, though, then we can either:
Find the closest event to that offset and just use that as our range
(in which case it wouldn't be a perfect 20 minute period), or
Predict what the value would have been for that offset using a rise over run calculation
What do you guys think would be the best approach? Any advice is greatly appreciated!
I need to calculate the percentile rank of a particular value against a large number of values filtered in various different ways. The data is all stored on Parse.com, which has a limitation of returning a maximum of 1000 rows per query. The number of values stored is likely to exceed well over 100,000.
By 'percentile rank', I mean I need to calculate the percentage of values that the provided value is greater than. I am not trying to calculate the value of a provided percentile. For example, given a list of values {20, 23, 24, 29, 30, 31, 35, 40, 40, 43} the percentile rank of the provided value 35 is 70%. The algorithm for this is simply the rank of the value / count of values * 100. Not sure if 'percentile rank' is the correct terminology for this.
I have considered a couple of different approaches to this. The first is to pull down the full list of values (into Parse Cloud) and then calculate the percentile rank from there, then filter the list and calculate again, repeating the last two steps as many times as required. The problem with this approach is it will not work once we reach 1000 values, which we can expect pretty quickly.
Another option, which is the best I can come up with so far, is to query the count of items, and the rank of the provided value. For example:
var rank_world_alltime = new Parse.Query("Values")
.lessThan("value", request.params.value) // Filters query to values less than the provided value, so counting this query will return the rank
.count();
var count_world_alltime = new Parse.Query("Values")
.count();
Parse.Promise.when(rank_world_alltime, count_world_alltime).then(function(rank, count) {
percentile = rank / count * 100;
console.log("world_alltime_percentile = " + percentile);
});
This works well for a single calculation, but I need to perform multiple calculations, and this approach very quickly becomes a lot of queries. I expect to need to run about 15 calculations per call, which is 30 queries. All calculations need to complete in under 3 seconds before Parse terminates the job, and I am limited to 30 reqs/second, so this is very quickly going to become a problem.
Does anyone have any suggestions on how else I could approach this? I've thought about somehow pre-processing some of this but can't quite work out how to do so, as the filters will be based on time and location (city and country), so there are potentially a LOT of pre-calculations that will need to be run at regular intervals. The results do not need to be 100% accurate but something close.
I don't know much about parse, but as far as I understand what you say, it is some kind of cloud database thingy that holds your hiscores, and limits you 1000 rows per query, 3 seconds per job, and 30 queries per second.
In order to have approximate calculations and divide by 2 the number of queries, I would first of all cache the total (count_world_alltime, count_region,week, whatever). If you can save them somewhere locally. For numbers of 100K just getting the order of magnitude (thus not the latest updated number) should be good enough to get a percentile.
Maybe you can get several counts per query. However my lack of expertise in parse/nosql kind of stops me from being sure of this, you'll have to check their documentation. If it is possible however, for the case where you need percentiles for a serie of values all in the same category, I would
Order the values, let's call them a,b,c,d,e (once ordered)
Get the number of values between the intervals [0,a] [a,b] [b,c] [c,d] [d,e]
Use the cached total to get the percentiles (where Nxy is the number of values in [x,y]) :
Pa = 100 * N0a / total
Pb = 100 * ( N0a + Nab ) / total
Pc = 100 * ( N0a + Nab + Nbc ) / total
and so on...
If you need a value ranked worldwide, the other per region, some per week others over all times, etc, this doesn't apply. In that case I don't think you can get below 1 query/number, with caching the totals.
I'm writing a system to handle messaging.
One of the options of a user is DND (Do Not Disturb) where a user can define a time range where he should not be alerted (such as 22:00 - 08:00).
When I perform a query on users, I wish to filter out the users which currently are on DND.
In each user's document, I define a field to hold the time in seconds:
{dnd: {start: 22*3600, end: 8*3600}}
I'm not sure how to perform the query itself (the following sample will not work due to overlapping midnight)
var current; // holds current time in seconds
db.user.find({$or:[{"dnd.start":{$gt:current}},{"dnd.end":{$lt:current}}]});
A different approach to this might be to store a "blacklist" of times as an array and query that the current time is not one of those elements. It depends on how granular you need this to be. Hours or half hours may be reasonable, as far out as per minute is not too bad.
So to generate the "blacklist" per minute you could do, as JavaScript code but the principles are easy to convert:
var start = 22 * 60;
var end = 8 * 60;
var dnd = [start];
do {
start++;
if ( start == 1440 )
start = 0;
dnd.push( start );
} while ( start != end );
db.user.update({},{ "$set": { "dnd": dnd } },true)
Essentially setting the "blacklist" against the user record.
Then when you query for say 1:30 in the morning, or the 90th minute you would do:
db.user.find({ "dnd": { "$ne": 90 })
And since the "blacklist" contains that value then you do not return the user records where that value would be in the list. But for a time beyond the "dnd" range it would return:
db.user.find({ "dnd": { "$ne": 481 })
Clearly you would generally want to exclude the array element when calling up details for the user record, but that is a simple matter of projection.
Is there a clever way to determine, say an array index, that falls within a given range? The application is similar to a playlist for a single video file with a set of from/to times that denote a "chapter".
i.e. Chapters:
00:01 - 00:30 : Call To Order
00:31 - 00:45 : Pledge of Allegence
00:46 - 02:25 : Opening Remarks
02:26 - 32:07 : Old Business
etc., etc., etc.
I have a list of these items on the page, and as the player reports where in the video it is currently playing by returning the current timestamp, I need to use jQuery to highlight the LI of the "chapter" in which the currently video timestamp falls. So if the video is currently at 1:15, that's "Opening Remarks", and the 3rd list item would be highlighted.
I've tried a number of approaches, but ultimately use PHP to write a huge series of IF/ELSEs because a playlist could have anywhere from 5 to 100 different Chapters in it and can be modified by the user at any time.
Ideally, I'd like an array using the Start time as the Key and chapter as the value, and a function that returns the first index that is >= the current timestamp. Is there any clever approach to accomplishing this? My way "works", but good God, its inefficient, running through 100 if/elses 10 times per second.
P.S. I should mention that all values are actually in seconds, with the question using H:M:S for clarity. Ultimately, I'm trying to understand how to select an array index if it falls within a given range.
Something like this:
var chapters = {
1: "callToOrder",
31: "pledgeOfAllegiance",
46: "openingRemarks",
146: "oldBusiness",
}
function currentChapter(seconds) {
var start, found = Infinity;
for (start in chapters) {
if (start <= seconds && start < found) {
found = start;
}
}
return (found === Infinity) ? null : chapters[found];
}
It will run in linear time in the number of chapters. In practice, this should be acceptable. If it isn't, then you could replace chapters with an array of objects and perform a binary search.
I am in charge of a website, and I have set up a "Quote of the Day" which currently is quite simplistic. See Here (on the right of the page)
What it currently does is it gets the Day of the month and the month, and normalises to one, then multiplies by the number of quotes (stored in an xml file) and rounds down. While this method will give me the same quote whichever machine I am on (something a random number generator could never do) it has been pointed out to me that this method is flawed. If you consider January the first couple quotes are going to be the same, 1*1/360, 2*1/360, 3*1/360, thus the quote isn't unique.
Can anyone think of a better way to select a quote of the day?
Fun question. Instead of relying on days of the month, why not count days since a given date? JS provides a pretty good property for that: getTime(), which gives you the number of milliseconds since 12am UTC on Jan. 1 1970, which you can convert to days with some simple division.
The only thing that complicates it is that if you expect your quotes to shift at midnight (and who doesn't?), you have to take into account the timezone. Again, JS provides that with getTimezoneOffset(), which gives the number of minutes ahead or behind the user's locale is compared to UTC. If you want ALL users to flip at the same time, regardless of where they live, just set this to a static value.
Your code could look something like this:
var intQuoteCount = 51; // The number of quotes in your library
var dtNow = new Date();
var intTZOffset = dtNow.getTimezoneOffset() * 60000; // automatically adjust for user timezone
var intNow = dtNow.getTime() - intTZOffset;
var intDay = Math.floor(intNow / 86400000); // The number of 'local' days since Jan 1, 1970
var intQuoteToDisplay = intDay % intQuoteCount;
True, determinism is something "a random number generator could never do". Fortunately (for this case, at least), programming languages provide pseudo-random number generators, not the real thing. The pseudo-random numbers are generated by doing a bunch of calculations on a "seed" value.
To get a repeatable "random" selection, then, all you need to do is set the seed in a way which is consistent for each day - I would suggest using the date, in "yyyymmdd" format, as the seed, but any other number which will be unchanged over the course of a day will work just as well.
Once you have your seed, tell the PRNG to use it with the command srand(mySeed); and you'll get the same sequence of "random" numbers from rand() every time (until mySeed changes).
If you want to show the quotes in order, you could get the current Julian Day number, which will increase by one each day, and take the reminder after dividing it by the number of quotes as the number of today's quote. If you want to show all quotes but the order of them to change each cycle, you can xor the quote number and rearrange the bits using some logic that you get from the quotient of the division.
You could try rounding up on an even day and rounding down on an odd day. But I'm am sure there is better ways, this is just quick suggestion.
Also you could try using the current day of the year in the calculation as this is unique for each new day in the year as opposed to repeating each month.
Do you have to limit yourself to having a cycle of 360 days? If you have for example 500 quotes. some might never be used.
How about- Every day pick a random number between 1 and #OfQoutes, use it as the quote of day index, and mark it as "used in current cycle".
Next time when you pick a number, if you pick a quote that is marked as "used in current cycle" re-pick until you get a number of quote which isn't marked so. When all quotes are marked, un-mark all of them.
This will ensure you're going through all quotes in each cycle, together with randomness, and it will obviously work for any number of quotes.
<body onLoad="thoughts_authors()">
<script>
function thoughts_authors()
{
var authors=new Array()
authors[0] = "Charles Schulz";
authors[1] = "Jack Wagner";
authors[2] = "Mark Twain";
authors[3] = "Oscar Wilde";
authors[4] = "David Letterman";
authors[5] = "Lily Tomlin";
var thoughts=new Array()
thoughts[0] = "Good Day Is Today";
thoughts[1] = "Style Is What You Choose";
thoughts[2] = "Be The Best Version Of You.";
thoughts[3] = "Truth Along Triumphs.";
thoughts[4] = "How can Life Be Devastating When YOU Are Present in It.";
thoughts[5] = "Believe In What You Say";
index = Math.floor(Math.random() * thoughts.length);
alert(thoughts[index]+ "-" + authors[index]);
}
</script>
THIS WILL GENERATE RANDOM QUOTES ALONG WITH RANDOM AUTHORS