Calculate number of data received in past 30 seconds - javascript

I have a websocket where i receive price of stock randomly like 300ms or sometimes 1 second.I want to calculate how many price I received in past 30 seconds only.
var arr = [];
function onReceive(price) {
var timestamp = Number(new Date());
arr[timestamp] = [];
arr[timestamp].push(price);
if (arrarr[timestamp].length > 1000) {
arr.shift();
}
}
Now I just want to count how many price is received in last 30 seconds , I cannot come up with any logic.
I tried something like slicing last 30 items in array and calculating difference between last time stamp and -30 timestamp , which tells me how much time it took to receive 30 price ticks ,but i dont know how to calculate how to find how many ticks received in past 30 seconds , any ideas please.thank you.
arr[timestamp][arr[timestamp].length-1].key-arr[timestamp][0].key;

Personally I would create some sort of named instance for a log item, holding the UNIX timestamp and the price.
To retrieve anything in the last X seconds, you'd get the current UNIX timestamp, subtract X * 1000 from it, and use .filter() do a reverse iteration to retrieve all items where the timestamp is greater than that.
EDIT: As Robby pointed out, there's no need to search through the entire array as the timestamps are guaranteed to be in increasing order. By iterating in reverse, we can exit the loop when we find the first result outside of the desired window.
var priceLog = [];
function PriceLogItem(price) {
this.price = price;
this.timestamp = new Date().getTime();
}
function onReceive(price) {
priceLog.push(new PriceLogItem(price));
if (priceLog.length > 1000) log.shift();
}
function getPriceLogsSince(secondsAgo) {
let millisecondsAgo = secondsAgo * 1000;
let time = new Date().getTime() - millisecondsAgo;
let result = [];
for (let i = priceLog.length - 1; i >= 0; i--) {
if (priceLog[i].timestamp >= time) result.push(priceLog[i]);
else break;
}
return result;
}
//Usage
let priceLogs = getPriceLogsSince(30); //Get all logs within past 30 seconds
console.log(priceLogs);

Related

Determining time remaining until bus departs

For our digital signage system, I'd like to show how long until the next bus departs. I've built the array that holds all the times and successfully (maybe not elegantly or efficiently) gotten it to change all that to show how much time is remaining (positive or negative) until each listed departure.
I need a nudge in the right direction as to how to determine which bus is next based on the current time. If there is a bus in 7 minutes, I only need to display that one, not the next one that leaves in 20 minutes.
I was thinking perhaps a for loop that looks at the array of remaining times and stops the first time it gets to a positive value. I'm concerned that may cause issues that I'm not considering.
Any assistance would be greatly appreciated.
UPDATE: Unfortunately, all the solutions provided were throwing errors on our signage system. I suspect it is running some limited version of Javascript, but thats beyond me. However, the different solutions were extremely helpful just in getting me to think of another approach. I think I've finally come on one, as this seems to be working. I'm going to let it run over the holiday and check it on Monday. Thanks again!
var shuttleOrange = ["09:01", "09:37", "10:03", "10:29", "10:55", "11:21", "11:47", "12:13", "12:39", "13:05", "13:31", "13:57", "14:23", "14:49", "15:25", "15:51", "16:17", "16:57", "17:37", "18:17"];
var hFirst = shuttleOrange[0].slice(0,2);
var mFirst = shuttleOrange[0].slice(3,5);
var hLast = shuttleOrange[shuttleOrange.length-1].slice(0,2);
var mLast = shuttleOrange[shuttleOrange.length-1].slice(3,5);
var theTime = new Date();
var runFirst = new Date();
var runLast = new Date();
runFirst.setHours(hFirst,mFirst,0);
runLast.setHours(hLast,mLast,0);
if ((runFirst - theTime) >= (30*60*1000)) {
return "The first Orange Shuttle will depart PCN at " + shuttleOrange[0] + "."
} else if (theTime >= runLast) {
return "Orange Shuttle Service has ended for the day."
} else {
for(var i=0, l=shuttleOrange.length; i<l; i++)
{
var h = shuttleOrange[i].slice(0,2);
var m = shuttleOrange[i].slice(3,5);
var departPCN = new Date();
departPCN.setHours(h,m,0);
shuttleOrange[i] = departPCN;
}
for(var i=shuttleOrange.length-1; i--;)
{
//var theTime = new Date();
if (shuttleOrange[i] < theTime) shuttleOrange.splice(i,1)
}
var timeRem = Math.floor((shuttleOrange[0] - theTime)/1000/60);
if (timeRem >= 2) {
return "Departing in " + timeRem + " minutes."
} else if (timeRem > 0 && timeRem < 2) {
return "Departing in " + timeRem + " minute."
} else {
return "Departing now."
}
}
You only need to search once to find the index of the next scheduled time. Then as each time elapses, increment the index to get the next time. Once you're at the end of the array, start again.
A sample is below, most code is setup and helpers. It creates a dummy schedule for every two minutes from 5 minutes ago, then updates the message. Of course you can get a lot more sophisticated, e.g. show a warning when it's in the last few minutes, etc. But this shows the general idea.
window.addEventListener('DOMContentLoaded', function() {
// Return time formatted as HH:mm
function getHHmm(d) {
return `${('0'+d.getHours()).slice(-2)}:${('0'+d.getMinutes()).slice(-2)}`;
}
var sched = ["09:01", "09:37", "10:03", "10:29", "10:55", "11:21", "11:47",
"12:13", "12:39", "13:05", "13:31", "13:57", "14:23", "14:49",
"15:25", "15:51", "16:17", "16:57", "17:37", "18:17","21:09"];
var msg = '';
var msgEl = document.getElementById('alertInfo');
var time = getHHmm(new Date());
var index = 0;
// Set index to next scheduled time, stop if reach end of schedule
while (time.localeCompare(sched[index]) > 0 && index < sched.length) {
++index;
}
function showNextBus(){
var time = getHHmm(new Date());
var schedTime;
// If run out of times, next scheduled time must be the first one tomorrow
if (index == sched.length && time.localeCompare(sched[index - 1]) > 0) {
msg = `Current time: ${time} - Next bus: ${sched[0]} tomorrow`;
// Otherwise, show next scheduled time today
} else {
// Fix index if rolled over a day
index = index % sched.length;
schedTime = sched[index];
msg = `Current time: ${time} - Next bus: ${schedTime}`;
if (schedTime == time) msg += ' DEPARTING!!';
// Increment index if gone past this scheduled time
index += time.localeCompare(schedTime) > 0? 1 : 0;
}
msgEl.textContent = msg;
// Update message each second
// The could be smarter, using setInterval to schedule running at say 95%
// of the time to the next sched time, but never more than twice a second
setInterval(showNextBus, 1000);
}
showNextBus();
}, false);
<div id="alertInfo"></div>
Edit
You're right, I didn't allow for the case where the current time is after all the scheduled times on the first running. Fixed. I also changed all the string comparisons to use localeCompare, which I think is more robust. Hopefully the comments are sufficient.
I have used filter for all shuttle left after the right time and calculated how much time left for the first one.
var shuttleOrange = ["09:01", "09:37", "10:03", "10:29", "10:55", "11:21", "11:47", "12:13", "12:39", "13:05", "13:31", "13:57", "14:23", "14:49", "15:25", "15:51", "16:17", "16:57", "17:37", "18:17"];
var d = new Date();
var h = d.getHours();
var m = d.getMinutes();
var remainShuttle = shuttleOrange.filter(bus => bus.substring(0,2) > h || (bus.substring(0,2) == h && bus.substring(3,5) > m));
var leftMinutes = (parseInt(remainShuttle[0].substring(0,2))*60 + parseInt(remainShuttle[0].substring(3,5)) - (parseInt(h) *60 + parseInt(m)));
console.log(parseInt(leftMinutes / 60) + " hours and " + leftMinutes % 60 +" minutes left for next shuttle");

Comparing current and next element of array and returning time difference

This is my array. Its length is about 9000. This is what a small bit of it looks like:
foreach_arr = ["21:07:01.535", "21:07:01.535", "21:07:26.113"]
There are a few occurences where the times diff is greater than a minute, and that is when I want to grab those times. And later use those times to get certain indices from another array. i.e "array"
I'm also using moment.js for time parsing.
Expected result: array = [8127, 9375, 13166, 14182]
Actual result: array = [8127, 13166]
Can't seem to find the issue here, I am getting 2 results when im supposed to be getting 4.
If the whole array is needed for troubleshooting, ill add it if I can.
var xx = foreach_arr.length - 1;
for(var z = 0; z < xx; z++) {
var current_row = foreach_arr[z];
var next_row = foreach_arr[z + 1];
var msElapsedTime = moment(next_row,"HH:mm:ss.SSS").diff(moment(current_row, "HH:mm:ss.SSS")) / 1000;
if(msElapsedTime > 60) {
attempt_indices.push(foreach_arr[z]);
}
}
for(var x = 0; x < attempt_indices.length; x++) {
array.push(newdata.indexOf(attempt_indices[x]));
}
Since the OP doesn't really need my code anymore, I'm posting it here to remove the downvote as much as anything else :)
const foreach_arr = ["21:07:01.535", "21:07:01.535", "21:07:26.113", '22:01:01.000'];
let processedForeach_arr = [];
let gtOneMinuteDiff = [];
foreach_arr.forEach((elem1, index1) => {
// elem1.split(':') turns foreach_arr[0] into ['21', '07', '01.535']
const splitElementArray = elem1.split(':');
let timeInMs = 0;
// this changes ['21', '07', '01.535'] into [75600000, 420000, 1535]
splitElementArray.forEach((elem2, index2) => {
if (index2 === 0) { // elem2 is hours. 3.6M ms per hour.
timeInMs += parseFloat(elem2) * 60 * 60 * 1000;
} else if (index2 === 1) { // elem2 is minutes. 60K ms per minute.
timeInMs += parseFloat(elem2) * 60 * 1000;
} else if (index2 === 2) { // elem2 is seconds. 1K ms per second.
timeInMs += parseFloat(elem2) * 1000;
} else {
throw `Expected array element formatted like HH:MM:SS.ms. Error on
element ${elem1}.`;
}
});
processedForeach_arr.push(timeInMs);
let timeDiff = processedForeach_arr[index1 - 1] - processedForeach_arr[index1];
if (Math.abs(timeDiff) > 60000) {
gtOneMinuteDiff.push(timeDiff);
}
});
To get the difference in milliseconds between foreach_arr[n] and foreach_arr[n+1], this code will
split each element of foreach_arr into 3 strings (hours, minutes, and seconds + milliseconds)
run parseFloat on each of those values to convert them to a number
convert all numbers to milliseconds and add them together
compare each consecutive value and return the difference.
Ok, I got this far and my son needs me. I'll finish out the code asap but you might beat me to it, hopefully the instructions above help.
turns out my code wasn't wrong. Just my idea of the whole proccess.
array = [8127, 13166]
is what I initialy get. With this, I use indexOf on my other array to eventually get my array as expected:
var another_test_arr = [];
for(var v = 0; v < array.length ; v++) {
var find = foreach_arr.indexOf(attempt_indices[v]);
another_test_arr.push(array[v], newdata.indexOf(foreach_arr[find + 1]));
}
Result: array = [8127, 9375, 13166, 14182]

Getting the average price of OPSkins pricelist via NodeJS

I want to somehow get the average price of every skin in this list
My question arises is how would one use the use dates and the prices to get the average price of 60 days?
In my idea I would parse the JSON for every item/object and get the dates and prices, then somehow loop through every date and add up the prices then divide by the days.
But I suppose my idea doesnt even need the dates but just the prices, though what difference does average and median give? Because I hear people use the word median for pricing rather than average.
const minimumDate = getMinimumDate();
for(let item in list){
let count = 0;
item['average'] = 0;
for(let date in item){
if(parse(date) >= minimumDate){
item.average += date.price;
count++;
}
}
item.average /= count;
}
getMinimumDate is a function that gives you a date based on today less N days, in your case 60 days, implement it.
parse is a function that parse string to a date.
The median is the value in the middle of the highest and the minimum values in a sorted list.
The average it's the most common value.
1,1,1,2,3,4,6
The average is 18 / 7 = 2'....
There are 7 numbers, the median is the number in the position 7/2 + 1, so our median is 2 due to it is in 4th position.
If the list length is pair take two numbers add them and divide:
1,1,2,3,4,6
Take the two middles, 2+3 and divide by 2, so the median is 2.5
Thanks to #jesusgn90 answer I figured it out and made it look like so:
const request = require("request");
var url = 'https://files.opskins.media/file/opskins-static/pricelist/578080.json';
request({
url: url,
json: true
}, (err, res, body) => {
if (!err && res.statusCode === 200) {
var cur = new Date(),
7daysbefore = cur.setDate(cur.getDate() - 7);
var parsed = JSON.parse(JSON.stringify(body));
for (let item in parsed) {
parsed[item]['average'] = 0;
count = 0;
for (date in parsed[item]) {
if(new Date(date) >= cur){
parsed[item].average += parsed[item][date].price;
count++;
}
}
parsed[item].average = Math.floor(parsed[item].average / count);
}
}
fs.writeFile("test.json", JSON.stringify(parsed), function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
});
});

JavaScript Array - all index over 0 are empty after loop

I have an array of date/timestamps saved as seconds, I'm looking to count the number of items that are between two timestamps (all times are assumed to be at midnight). I've cut down a larger function to the section that the problem seems to reside, let me know if you need any additional code.
var fullDay = 86399;
var end = parseInt(dataArray[0]) + parseInt(fullDay);
for (var i = 0; i < numberOfDays; i++) {
dataSegments[i] = sensorEventTotal(dataArray, end, previousEnd);
previousEnd = end;
end = parseInt(end) + parseInt(fullDay);
}
console.log(dataSegments.toString());
SensorEventTotal:
function sensorEventTotal (dataArray, end, previousEnd){
var counter = 0;
$.each(dataArray, function(i, item) {
if (parseInt(item) < end && parseInt(item) > previousEnd) {
counter++;
}
});
previousEnd = end;
return counter;
}
What I'm trying to do is to take the first date/time stamp and add 24 hours (fullDay value is 24 hours in seconds), I'm then looking to use that "end time" as the start point for the next loop with another 24 hours added onto that and so on.
In the end I'd want an array where each index stores the number of occurrences for each day e.g. dataSegments = [23,123,32,34] - so 23 events on day one, 123 events on day two etc.
At the moment this is the result I'm getting for dataSegments:
115,0,0,0,0,0
EDIT:
Sample of data in dataArray:
1496077569,1496077568,1496077567,1496077564,1496077563,1496077562,1496072956
Full array:
1496077569,1496077568,1496077567,1496077564,1496077563,1496077562,1496072956,1496072955,1496072951,1496072950,1496072949,1496072948,1496072809,1496072805,1496072804,1496072803,1495815090,1495815089,1495815088,1495807282,1495807281,1495807280,1495807279,1495807277,1495807276,1495807275,1495807274,1495807273,1495807267,1495807266,1495807265,1495805409,1495805408,1495805407,1495805406,1495805381,1495805380,1495805379,1495803061,1495803060,1495803059,1495803059,1495803000,1495802999,1495802998,1495786283,1495786282,1495786281,1495728263,1495728262,1495728261,1495728258,1495728257,1495728256,1495727698,1495727697,1495727696,1495727695,1495727694,1495727693,1495727491,1495727490,1495727489,1495727486,1495727485,1495727484,1495724286,1495724285,1495724284,1495724279,1495724278,1495724277,1495720363,1495720358,1495720357,1495720356,1495719373,1495719372,1495719368,1495719367,1495719366,1495717302,1495717301,1495717299,1495717298,1495717297,1495717296,1495713310,1495713309,1495713308,1495713305,1495713304,1495713303,1495713303,1495707902,1495707901,1495707897,1495707896,1495707895,1495707615,1495707611,1495707610,1495707609,1495707608,1495704627,1495704626,1495704625,1495704623,1495704622,1495704621,1495704133,1495704132,1495704128,1495704127,1495704126
This is what I managed to come up with. I hope code is clear just from variable names alone, given that the logic is very similar to yours.
const SECONDS_IN_DAY = 24 * 3600;
let events = [1496077569,1496077568,1496077567,1496077564,1496077563,1496077562,1496072956,1496072955,1496072951,1496072950,1496072949,1496072948,1496072809,1496072805,1496072804,1496072803,1495815090,1495815089,1495815088,1495807282,1495807281,1495807280,1495807279,1495807277,1495807276,1495807275,1495807274,1495807273,1495807267,1495807266,1495807265,1495805409,1495805408,1495805407,1495805406,1495805381,1495805380,1495805379,1495803061,1495803060,1495803059,1495803059,1495803000,1495802999,1495802998,1495786283,1495786282,1495786281,1495728263,1495728262,1495728261,1495728258,1495728257,1495728256,1495727698,1495727697,1495727696,1495727695,1495727694,1495727693,1495727491,1495727490,1495727489,1495727486,1495727485,1495727484,1495724286,1495724285,1495724284,1495724279,1495724278,1495724277,1495720363,1495720358,1495720357,1495720356,1495719373,1495719372,1495719368,1495719367,1495719366,1495717302,1495717301,1495717299,1495717298,1495717297,1495717296,1495713310,1495713309,1495713308,1495713305,1495713304,1495713303,1495713303,1495707902,1495707901,1495707897,1495707896,1495707895,1495707615,1495707611,1495707610,1495707609,1495707608,1495704627,1495704626,1495704625,1495704623,1495704622,1495704621,1495704133,1495704132,1495704128,1495704127,1495704126];
events = events.reverse();
let midnight = events[0] - events[0] % SECONDS_IN_DAY; // midnight before the first event
const eventsPerDay = []; // results array
const nrDays = 7; // lets count events for one week
let daysCounted = 0, eventsChecked = 0;
while (daysCounted < nrDays) {
midnight += SECONDS_IN_DAY;
let currentEvent = events[eventsChecked];
let eventsInThisDay = 0;
while (currentEvent < midnight) {
eventsInThisDay++;
eventsChecked++;
currentEvent = events[eventsChecked];
}
eventsPerDay[daysCounted] = eventsInThisDay;
daysCounted++;
}
console.log(eventsPerDay);
Notice that I reverse the sample array before running my execution. That is because your sample starts at May 29 and ends at May 25, so it's running backwards in time.
I encourage you to try your own code on a reversed array, might very well be the case that your solution is correct.
If you do not want to reverse the array, you could "reverse the counting" by going from the latest midnight to the first midnight, subtracting 1 day on each iteration.
In my opininion (and coming example), you can do it a bit simpler. Also, I've noticed a little problem in your function: if your dataArray and number of days (let's call them N) were big, you would have to iterate over the data array N number of times. It could become inefficient. Luckily you can do it in one loop iteration:
let sensorEventTotal = (data, start, daysNum) => {
// We create array of length daysNum filled with 0's.
let days = new Array(daysNum);
days.fill(0);
for(let entry of data) {
// If below the start timestamp, continue loop.
if(entry < start) continue;
// We calculate which day it is.
let index = parseInt((entry - start) / fullDay);
// We check if the entry is not from days we do not count.
if(index < daysNum)
days[index]++;
}
return days;
}
Code with working examples: http://jsbin.com/lekiboruki/edit?js,console.
EDIT: You didn't mention if your dataArray is sorted. My answer would also work on unsorted arrays.

Incrementing a number smoothly with a variable time period in JS

I have a really simple JS counter which I display on a dashboard like screen which does the following:
Every 5 minutes it makes an jsonp call and retrieves a "total" number
It then displays this number to the screen by incrementing the last total displayed till it is equal to the new total. (the number can only ever increase)
I'm having some trouble with making the number increment smoothly. What I would like to do is find a delta (i.e. New total - old total) and increment the number gradually over the 5 minutes till the next call so it looks like a nice smooth transition.
Any ideas on how I can do this?
Currently some of my code looks like this (This block get's called every 5mins. And yes, it's in dire need of a refactor...)
var LAST_NUMBER_OF_SESSIONS = null;
var five_minutes_in_seconds = 300;
var new_number_of_sessions;
$.getJSON('http://blah.com/live_stats/default_jsonp.aspx?callback=?', function(data) {
if(LAST_NUMBER_OF_SESSIONS === null){
LAST_NUMBER_OF_SESSIONS = data.total_sessions;
}
new_number_of_sessions = data.total_sessions;
var delta = Math.floor(new_number_of_sessions - LAST_NUMBER_OF_SESSIONS);
var time_interval = (five_minutes_in_seconds / delta) * 1000;
var old_value = LAST_NUMBER_OF_SESSIONS;
var new_value = null;
sessions_interval = setInterval(function (){
new_value = parseInt(old_value, 10) + 1;
$('#stats').text(new_value);
old_value = new_value;
if(new_value >= new_number_of_sessions){
clearInterval(sessions_interval);
}
}, time_interval);
LAST_NUMBER_OF_SESSIONS = new_value;
});
}
This code it seems to increment the number very quickly at the start of the 5min period and then stop so it's not exactly right...
Try this:
var total = 0,
delta = 0,
stats = $('#stats').text( total );
function increment() {
var v = +stats.text();
if ( v < total ) {
stats.text( v + 1 );
} else {
$.getJSON('http://...', function(data) { // added data here
delta = Math.floor( 300000 / ( data.total_sessions - total ) );
total = data.total_sessions;
});
}
setTimeout(increment, delta);
}
Update:
In order to test my code, I had to simulate the JSON reponse - I used an array of numbers. See here: http://jsfiddle.net/simevidas/MwQKM/
(In the demo, I use an interval of 5 seconds instead of 5 minutes.)
I am not exactly sure why your code doesn't work as expected, although I suspect that it has to do with line LAST_NUMBER_OF_SESSIONS = new_value;. I wrote something similar and it works fine. It's not that different from what you have, minus that last line of code.

Categories

Resources