Pulling values from an array based on date? - javascript

I have an array of data points, [date, value], like so...
data_points = [[1310279340, 1], [1310279340, 1]]
I need to create an array based on "milliseconds ago", with ten values for each second, or a value for every 100ms going backwards.
The new array's values will look like, [ms ago, value], like so...
ms_ago_points = [[0,3],[100,6],[200,7]]
So the last value in that array represents [200ms ago, value of 7].
I'm having a hard time figuring out how to get "value from Xms ago" based on date values in the first array. If needed I might be able to get the initial date/values in a format other then an array if it would be easier to poll for data.
Thanks for any guidance!!
edit: I'm looking to repeat the same value between dates for every 100ms tick that lands between them.

var now = Date.now(),
l = data_points.length,
ms_ago_points = [];
for ( var c = 0; c < l; c++ ) {
ms_ago_points.push([now - data_points[c][0],data_points[c][1]);
}
Maybe you need to sort the ms_ago_points afterwards, but this should give you your desired array.
However: I'd seriously suggest you not to work with multi-dimesional arrays but objects instead:
ms_ago_points= [{ms: 0, value: 3},{ms:100, value: 6}...]
*edit: This of course assumes that your data_points are already in 100ms steps, otherwise you'd have to implement an interpolation :)

I believe this meets your requirements:
function msFromDataPoints(nowTime, dataPoints) {
var d = dataPoints.length,
i = 0,
anchor = Math.floor(nowTime.getTime() / 100) * 100,
ms = anchor,
msArr = [];
while (d--) {
while (ms >= data_points[d][0] * 1000) {
msArr.push([anchor - ms, dataPoints[d][1]];
ms -= 100;
}
}
return msArr;
}
See it in a Js Fiddle.
Note: I find the data structures to be a little strange. An object for the input seems best:
[{date: 1310279340, value: 1}, {date: 1310279340, value: 1}]
And your output array doesn't need the milliseconds at all, as simply [1, 1, 5, 5, 3, 2 4] (or whatever) would be understood to mean millisecond indexes starting at 0 and increasing by 100. If absolutely required, you could use a sparse array:
result = [];
result[0] = 1;
result[100] = 1;
result[200] = 5; // and so on

Related

Loop through array of objects and return accumulated data from those objects

So I have an array that comes from my database. An array has an object inside. I have hours and employee id as well as a list of employees on the web page. When I click on employee I want to see that number of hours that assigned to that employee.
var makeup_hrs = api_resp.makeup_data[key];
for (var i = 0; i < makeup_hrs.length; i++) {
var obj = makeup_hrs[i];
console.log(obj);
for (var o in obj) {
var y = obj[o];
console.log("make up hours ", y, "id: ", emp_id)
var x = document.getElementById("makeUpHours").innerHTML = y;
console.log(x);
// $('#makeUpHours').html(y);
}
}
Anytime I print make up hours and emp_id - it gives me the number of that employee and his hours value. But when I innerHTML it only shows the last hours value , not a specific hour to a specific employee.
like that(console output) I have only 2 employees for now in my database:
make up hours 4 id: 2891
make up hours 7 id: 1978
here is my html (it is inside of the modal - bootstrap)
<div class="form-group"> <label class="col-sm-3"> Hours </label>
<span id="makeUpHours"></span></div>
when I click on the icon - modal pops up . Every icon is assigned to an employee id
Employee id comes from a one array and hours from another one. Somehow when I console log 2 values together they assign the right id number to the right hour number.
You are setting innerHTML on every iteration rather than adding to it (so only the last iteration will be shown).
Here's a sample solution:
// sample data
const employees = [{
name: 'Bob',
hours: 10
}, {
name: 'Jane',
hours: 15
}, {
name: 'John',
hours: 20
}]
const ul = document.getElementById('employees')
// how you want to represent an employee's info
const stringifyData = employee => `${employee.name}: ${employee.hours} hours`
// add employee HTML
const addEmployee = str => {
ul.innerHTML += `<li>${str}</li>`
}
// iterate
employees.map(stringifyData).forEach(addEmployee)
<ul id="employees"></ul>
I prefer to separate data transformations from DOM manipulations (easier to test) but you could of course do both in one iteration.
Let's do some theoretical stuff to understand the problem better, for understanding an underlying problem is key to finding a solution.
So imagine that you have an array of objects:
[{
id: 1,
x: 10,
}, {
id: 2,
x: 20,
}, {
id: 3,
x: 30,
}];
and as a result, you want this HTML markup to put into innerHTML property of an arbitrary DOM element:
<p>id: 1, x: 10</p>
<p>id: 2, x: 20</p>
<p>id: 3, x: 30</p>
(mind absence of a single common parent, which is valid for innerHTML)
You could go through an array of objects with a for loop, then through properties of each object with another for loop pretty much as you did, with only remark that you need to accumulate result somewhere outside of scope of any of those loops, but preferably in scope of the function that will change innerHTML of a target element. Something like this:
let result = '';
for (let i = 0; i < array.length; i++) {
result += `<p>id: ${array[i].id}, x: ${array[i].x}</p>`;
}
element.innerHTML = result;
but more suitable in your case.
Using for loops brings us to a practice widely followed in Javascript community these days: applying map and reduce (see Array#map and Array#reduce) to a collection of similarly typed elements. With this approach, the code would look like:
element.innerHTML = array.reduce((total, current) => `${total}<p>id: ${current.id}, x: ${current.x}</p>`, '');
which may look a bit convoluted, but gives exactly the same effect.
And remember: if you want to add something to a string (namely, concatenate), use +=; if you want to replace its value, use =.

Subtracting all the values inside an array from the first item

So i have this array of objects that looks like this:
let budgetData = [{title: "Monthly Income", amount: "2500"}, {title:
"rent", amount: "1000"},{title: "car", amount: "200"};
I am trying to some math like this:
2500 - 1000 - 200 = whatever this comes out too. You can continue to add amounts to this array until you have added your monthly expenses.
When you run this the first time with only two values the amount is what you would expect (ie. 2 - 1 = 1).
However add anymore than two amounts to the array it only subtracts whatever the last value is from the first value.(ie. 5 - 2 - 1 = 4).
let amount = [];
for (let i = 1; i < budgetData.length; i++){ amount =
budgetData[0].amount - budgetData[i].amount;
Console.log(amount) === 2300
So this code with the above info the answer comes out to: 2300 when I am expecting it to say 1300.
Where am I going wrong with this, also, is there some built in math function that will do what I am trying to do?
Each time through the loop you're throwing away what you calculated before, and overwriting amount with a new calculation. So what you end up at the very end is just subtracting the very last number from the first number.
Instead, you need to keep a running tally. Something like this:
let budgetData = [
{title: "Monthly Income", amount: "2500"},
{title: "rent", amount: "1000"},
{title: "car", amount: "200"}
];
let amount = budgetData[0].amount;
for (let i = 1; i < budgetData.length; i++){
amount = amount - budgetData[i].amount;
}
console.log(amount);
Alternatively you could reduce the array:
const total = budgetData.reduce((previous, current) => (previous.amount || previous) - current.amount);
If your budget objects implement a valueOf method, like this:
class Budget {
constructor(settings){
Object.assign(this, settings);
}
valueOf(){ return this.amount;}
}
budgetData = budgetData.map(el => new Budget(el));
It gets even more beautiful:
const total = budgetData.reduce((a,b) => a-b);

forEach unexpected token adding new property to existing array

I want to add a new proeprrty call total_days calculate using date_from and date_to but my forEach got an expected token error.
let applicants = [{
date_from: '2017-05-05',
date_to: '2017-05-10'
},{
date_from: '2017-05-08',
date_to: '2017-05-12'
}]
calculateDays = applicants.forEach(obj =>
applicants['total_days'] = (obj.date_from).diff(obj.date_to, 'days')+1;
)
No clue what's wrong here.
You didn't exactly clarify what you wanted but I tried to take a guess by your code.
My guess is that you wanted to create a new array of applicants from the old array of applicants but in the new array, you wanted to add a property to each object in that array that is the difference in days of the two dates.
To do so, you can use Array.prototype.map to map each item from your array to a new array.
I'm also using Object.assign to clone each object so that the original array is unmodified.
I'm also parsing the date strings into number. The parsed number is the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC. If I take the difference of the two numbers and divide that be the millisecondsInADay then I'll get how many days elapsed in between.
The result is then stored into a new array calculateDays.
Let me know if you need more clarification.
let applicants = [{
date_from: '2017-05-05',
date_to: '2017-05-10'
}, {
date_from: '2017-05-08',
date_to: '2017-05-12'
}]
const millisecondsInADay = 1000 * 60 * 60 * 24;
const calculateDays = applicants.map(obj => Object.assign({}, obj, {
total_days: ((
Date.parse(obj.date_to) - Date.parse(obj.date_from)
) / millisecondsInADay) + ' days'
}));
console.log(calculateDays);
Assuming you want to add a new property to all objects, you could use obj as variable with a new property.
applicants.forEach(obj => obj.total_days = obj.date_from.diff(obj.date_to, 'days') + 1);
// ^^^

Array incrementing Javascript / node js / mongodb

I'm trying to gather data from a MongoDB with Node JS to draw a graph later.
My goal is to collect all entries by hour of the day. In my collection there is a "created_at" field which stores a Date Object.
I'm trying to store the data in an array with 24 slots like this:
// padding the array for each hour of the day
var hours = new Array(23);
// defaulting the value for each hour to 0
for(var i=0; i<hours.length; i++){
hours[i] = 0;
}
db.collection.find({}, {"created_at": 1}, function(err, entry){
if (err){ doSomething(); }
else {
entry.forEach(function(item, index){
// get hour of the day from the Date object
h = item["created_at"].getHours();
h = parseInt(h);
// store hour of the day and count it up
hours[h]++;
console.log("#%s: %s", index, h);
});
}
});
console.log(hours);
Now when I log hours I get the array with the default values. ie [0, 0, 0, 0 ... 0]
I'm certain that the database has correct values as the console.log in the inner function gets correct data.
I suspect the problem is one of concurrency: the collection's .find method is asynchronous. So your console.log after the call to .find gets executed before the entry.forEach ever even executes. Try moving the console.log into the body of the else clause, after the forEach (which is synchronous), and you should see the result you're looking for.
Going forward, you'll have to employ promises or something to get the results you want.

How to randomly return associative array names based on its values

I've a set of campaigns that correspond to a number of "points." Looks something like this:
[ {"c1":4, "c2":8, "c3":25} ]
I want to randomly pick a campaign from this set. I'm assuming rand() will come into play at some point. However, I want the value of each to affect its chances of being picked.
So, for example, campaign "c2" should be picked twice as often as campaign "c1" (roughly). "c3" would be king, being most likely to be picked.
The number of campaigns and corresponding values may or may not be the same every time the script runs.
What's a good way to go about this?
That's easy.
Just create another map that have CDF value for each campaign. For your example it will be:
0.108: C1
0.324: C2
1: C3
Then get a random number between 0 and 1. Go through the map and find the smallest number that is larger than the random number (you can binary search it or create a sorted hash map that can give smallest larger number also)
Note that by adding the probabilities the last entry may not add to 1 (can be 0.999). Just set it to 1 manually.
Here's a function that solves this for you. It creates a weighting array that you can use with a random number to properly weight each item per it's weighted value.
var campaigns = {"c1":4, "c2":8, "c3":24};
function getWeightedRandomCampaign(list) {
var weighting = [];
var total = 0;
for (var item in list) {
weighting.push({key: item, value: list[item]});
total += list[item];
}
// generate random number between 1 and total
var rand = Math.floor(Math.random() * total);
// figure out which weighted slot it fits in
var cum = 0;
for (var i = 0; i < weighting.length; i++) {
cum += weighting[i].value;
if (rand < cum) {
return(weighting[i].key);
}
}
return(weighting[weighting.length - 1]);
}
You can see it work here: http://jsfiddle.net/jfriend00/ffwqQ/
Here's how it works.
It starts with the campaigns objects and the weighting values.
var campaigns = {"c1":4, "c2":8, "c3":24};
Then, it builds a temporary data structure that looks like this:
var weighting = [{key: "c1", value: 4}, {key: "c2", value: 8}, {key: "c3", value: 24}];
While creating that data structure, it keeps track of the running total of all weight values.
It then creates a random number between 0 and that total.
It then walks through the weighting array adding up the values to find the first cumulative value that exceeds the random number. When it finds that, this is the slot that was selected.

Categories