Is there a good way to loop through APIs? - javascript

There are too many loops in this API, which is causing it to run slowly.
this data is only for year i have to run same code for Day month week looping same code makes the code slower.
// ```GRAPH CALCULATION FOR YEAR```\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
let query = '';
graph_data = '';
let startOfYear = MOMENT().startOf('year');
let monthsForYear = [];
let year = [];
// Create an array of dates representing the start of each month in the year
for (let index = 0; index <= 11; index++) {
const add1Month = MOMENT(startOfYear)
.add(index, 'month')
.format('YYYY-MM-DDTHH:mm:SS.000+00:00');
monthsForYear.push(add1Month);
}
// Get the actual amount for each month
for (let i = 0; i < monthsForYear.length; i++) {
let j = i + 1;
let d = await PRISMA.orders.findMany({
where: {
created_at: {
gte: monthsForYear[i],
lte:
i === monthsForYear.length - 1 ? endOftheYear_date : monthsForYear[j],
},
},
select: { actual_amount: true },
});
// Calculate the total actual amount for the month
let total = 0;
d.forEach((el) => {
total += el.actual_amount;
});
year.push(total);
}
// Set the graph data to the calculated amounts
graphDataOfYear = year;

You execute asynchronous statements (using await) in a loop, which means they are executed consecutively: The second statement starts only after the first has completed. It may be faster if you execute them in parallel.
The first loop starts all statements in parallel, then all results are awaited together and the total actual amounts calculated in a second loop:
let statements = [];
for (let i = 0; i < monthsForYear.length; i++) {
let j = i + 1;
statements.push(PRISMA.orders.findMany({
where: {
created_at: {
gte: monthsForYear[i],
lte:
i === monthsForYear.length - 1 ? endOftheYear_date : monthsForYear[j],
},
},
select: { actual_amount: true },
}));
}
for (const d of await Promise.all(statements)) {
// Calculate the total actual amount for the month
let total = 0;
d.forEach((el) => {
total += el.actual_amount;
});
year.push(total);
}
The general pattern is:
let statements = [];
for (...) {
statements.push(/* asynchronous statement without await */);
}
for (const d of await Promise.all(statements)) {
/* d is the result of each asynchronous statement in turn */
}
It is very likely even faster if you can let PRISMA do the total actual amount calculation, because then only one number (the total actual amount) must be sent back to your Javascript code, whereas with your current code every order that exists in PRISMA is sent back for one of the months, and then again for one of the weeks, and for one of the days. But I am no PRISMA expert.

Related

What is the fastest format for a key in a JS object [Improved]

Backround Info
For a program I'm working on I need to track the path taken through a web. In this case, a web is defined a series of nodes, each node having zero or more child nodes. It's a web and not a tree because any node can point to any other and can be circular.
My program will start at one "entry point" node, and traverse through the web until it has taken a path that is considered "valid". All valid paths are stored in a series of nested maps, each map containing the keys of all possible next steps.
For example:
{ 0: {1: "success"} }
This nested map defines the path:
entryNode.children[0].children[1]
I have a minimal example of the traversal algorithm for benchmarking purposes:
// you can ignore this, it just helps me get some more info on the results
function getStandardDeviation (array) {
const n = array.length
const mean = array.reduce((a, b) => a + b) / n
return Math.sqrt(array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n)
}
//// values that can be converted to a 1-digit base-36 number
// let list = [30, 31, 32]
//// without base-36: 411ms
//// with base-36: 2009ms
//// values that can be converted to a 2-digit base-36 number
// let list = [36, 37, 38]
//// without base-36: 391ms
//// with base-36: 1211ms
//// arbitrary large numbers
let list = [10000, 10001, 10002]
//// without base-36: 4764ms
//// with base-36: 1954ms
//// I tried encoding to base 36 to reduce the key length, hence the keys like '1o' and '1p'
//// This seems to hurt the performance of short numbers, but help the performance of large ones
// list = list.map(n => n.toString(36))
let maps = {}
let currentMap = maps
list.forEach((n, i) => {
if (i === list.length - 1) {
currentMap[n] = "res1"
} else {
const tempMap = {}
currentMap[n] = tempMap
currentMap = tempMap
}
})
console.log(maps)
// store samples for stdev
let times = []
const samples = 1000
const operations = 100000
// collect samples for stdev calculation
for (let k = 0; k < samples; k++) {
const begin = process.hrtime()
// dummy variable to simulate doing something with the result
let c = ""
let current = maps
for (let i = 0; i < operations; i++) {
// simulate what the final algorithm does
for (let j = 0; j < list.length; j++) {
current = current[list[j]]
if (typeof current === 'string') {
c = current
}
}
current = maps
}
const end = process.hrtime()
// get the ms difference between start and end
times.push((end[0] * 1000 + end[1] / 1000000) - (begin[0] * 1000 + begin[1] / 1000000));
}
const stdev = getStandardDeviation(times)
let total = 0;
times.forEach(t => total += t)
console.log("Time in millisecond is: ", total.toFixed(2), `+-${stdev.toFixed(2)}ms (${(total - stdev).toFixed(2)}, ${(total + stdev).toFixed(2)})`)
The Question
While testing, I wondered if using shorter keys would be faster, since I'm guessing JS hashes them somehow before doing the lookup. And I found that different object keys resulted in drastically different performance, varying by about an order of magnitude, with the only difference being the size/characters used in map's keys. There's not an obvious pattern that I can see, though.
I laid out the different input lists and their results in the top of the benchmark source, but here's the actual maps used and their respective times:
// raw numbers
{ '30': { '31': { '32': 'res1' } } }
Time in millisecond is: 411.00 +-0.13ms (410.86, 411.13)
// converted to base-36
{ u: { v: { w: 'res1' } } }
Time in millisecond is: 2009.91 +-0.18ms (2009.72, 2010.09)
// raw numbers
{ '36': { '37': { '38': 'res1' } } }
Time in millisecond is: 391.52 +-0.16ms (391.36, 391.69)
// converted to base-36
{ '10': { '11': { '12': 'res1' } } }
Time in millisecond is: 1211.46 +-0.19ms (1211.27, 1211.65)
// raw numbers
{ '10000': { '10001': { '10002': 'res1' } } }
Time in millisecond is: 4764.09 +-0.17ms (4763.93, 4764.26)
// converted to base-36
{ '7ps': { '7pt': { '7pu': 'res1' } } }
Time in millisecond is: 1954.07 +-0.17ms (1953.90, 1954.25)
Why do these differeny keys result in such wildly different timings? I've tested it a lot and they are quite consistent
Note:
I'm using Node V16.15.0 for benchmarking

How do I filter the data sent by firestore

How do I filter the data in collection in Firestore
If the first letter is "+" then I want to get filtered in Income section if the first letter is "-" then I want to get filtered in Expenditure Section
I tried this, but not working:
const getUsers = async()=>{
total_income_amount = await db.collection("users").get().then((querySnapshot) => {
const sum = querySnapshot.docs.filter((item) => item > 0).reduce((a, b) => a + b.data().amount, 0)
return sum
})
}
I am getting the output as 0
and I want the output with two decimal places
EDIT
Here's my code:
total_amount = db.collection("users").get().then((querySnapshot) => {
var total_sum = 0;
var income_sum = 0;
var exp_sum = 0;
querySnapshot.docs.forEach(doc => {
const amount = doc.data().amount;
amount >= 0.0? income_sum += amount : exp_sum -= amount;
total_sum += amount;
});
return {total: total_sum, income: income_sum, expense: exp_sum }
}).finally(result => console.log("Total: ", result));
You can loop through the list of values and append the values once rather than looping through it 5 times with a reduce & filter
total_amount = db.collection("users").get().then((querySnapshot) => {
var total_sum = 0;
var income_sum = 0;
var exp_sum = 0;
querySnapshot.docs.forEach(doc => {
const amount = doc.data().amount;
amount >= 0.0? income_sum += amount : exp_sum -= amount;
total_sum += amount;
});
return {total: total_sum, income: income_sum, expense: exp_sum }
})
.finally(result => console.log("TOTALS", result);
EDIT
It's not good to make major changes to your Question
but in general, you can truncate all number's to a decimal place using toFixed() on the final output
https://www.w3schools.com/jsref/jsref_tofixed.asp
UPDATE
Ensure your numbers are converted to real numbers from user inputs with Number(value) if the typeof returned is not a number, you can know if it is valid or not.
Once this has been done, ensure you return the correct calls as needed as scripts also only fire once.
when rendering values inside HTML, you want to use an embedded <span> tag with the appropriate id tag rather than editing it via javascript

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]

Javascript: Find out of sequence dates

Consider this nested array of dates and names:
var fDates = [
['2015-02-03', 'name1'],
['2015-02-04', 'nameg'],
['2015-02-04', 'name5'],
['2015-02-05', 'nameh'],
['1929-03-12', 'name4'],
['2023-07-01', 'name7'],
['2015-02-07', 'name0'],
['2015-02-08', 'nameh'],
['2015-02-15', 'namex'],
['2015-02-09', 'namew'],
['1980-12-23', 'name2'],
['2015-02-12', 'namen'],
['2015-02-13', 'named'],
]
How can I identify those dates that are out of sequence. I don't care if dates repeat, or skip, I just need the ones out of order. Ie, I should get back:
results = [
['1929-03-12', 'name4'],
['2023-07-01', 'name7'],
['2015-02-15', 'namex'],
['1980-12-23', 'name2'],
]
('Namex' is less obvious, but it's not in the general order of the list.)
This appears to be a variation on the Longest Increase Subsequence (LIS) problem, with the caveat that there may be repeated dates in the sequence but shouldn't ever step backward.
Use case: I have sorted and dated records and need to find the ones where the dates are "suspicious" -- perhaps input error -- to flag for checking.
NB1: I am using straight Javascript and NOT a framework. (I am in node, but am looking for a package-free solution so I can understand what's going on...)
Here's an adaptation of Rosetta Code LIS to take a custom getElement and compare functions. We can refine the comparison and element-get functions based on your specific needs.
function f(arr, getElement, compare){
function findIndex(input){
var len = input.length;
var maxSeqEndingHere = new Array(len).fill(1)
for(var i=0; i<len; i++)
for(var j=i-1;j>=0;j--)
if(compare(getElement(input, i), getElement(input, j)) && maxSeqEndingHere[j] >= maxSeqEndingHere[i])
maxSeqEndingHere[i] = maxSeqEndingHere[j]+1;
return maxSeqEndingHere;
}
function findSequence(input, result){
var maxValue = Math.max.apply(null, result);
var maxIndex = result.indexOf(Math.max.apply(Math, result));
var output = new Set();
output.add(maxIndex);
for(var i = maxIndex ; i >= 0; i--){
if(maxValue==0)break;
if(compare(getElement(input, maxIndex), getElement(input, i)) && result[i] == maxValue-1){
output.add(i);
maxValue--;
}
}
return output;
}
var result = findIndex(arr);
var final = findSequence(arr, result)
return arr.filter((e, i) => !final.has(i));
}
var fDates = [
['2015-02-03', 'name1'],
['2015-02-04', 'nameg'],
['2015-02-04', 'name5'],
['2015-02-05', 'nameh'],
['1929-03-12', 'name4'],
['2023-07-01', 'name7'],
['2015-02-07', 'name0'],
['2015-02-08', 'nameh'],
['2015-02-15', 'namex'],
['2015-02-09', 'namew'],
['1980-12-23', 'name2'],
['2015-02-12', 'namen'],
['2015-02-13', 'named'],
];
console.log(f(fDates, (arr, i) => arr[i][0], (a,b) => a >= b));
This solution tries to get all valid sequences and returns the longes sequences for filtering the parts out.
It works by iterating the given array and checks if the values could build a sequence. If a value is given, which part result has a valid predecessor, the array is appended with this value. If not a backtracking is made and a sequence is searched with a valid predecessor.
act. array
value 7 3 4 4 5 1 23 7 comment
----- ------------------------ ---------------------------
7 7 add array with single value
3 7 keep
3 add array with single value
4 7 keep
3 4 add value to array
4 7 keep
3 4 4 add value to array
5 7 keep
3 4 4 5 add value to array
1 7 keep
3 4 4 5 keep
1 add array with single value
23 7 23 add value to array
3 4 4 5 23 add value to array
1 23 add value to array
7 7 23 keep
7 7 fork above, filter for smaller or equal and add value
3 4 4 5 23 keep
3 4 4 5 7 fork above, filter for smaller or equal and add value
1 23 keep
1 7 fork above, filter for smaller or equal and add value
function longestSequences(array, getValue = v => v) {
return array
.reduce(function (sub, value) {
var single = true;
sub.forEach(function (s) {
var temp;
if (getValue(s[s.length - 1]) <= getValue(value)) {
s.push(value);
single = false;
return;
}
// backtracking
temp = s.reduceRight(function (r, v) {
if (getValue(v) <= getValue(r[0])) {
r.unshift(v);
single = false;
}
return r;
}, [value]);
if (temp.length !== 1 && !sub.some(s => s.length === temp.length && s.every((v, i) => getValue(v) === getValue(temp[i])))) {
sub.push(temp);
}
});
if (single) {
sub.push([value]);
}
return sub;
}, [])
.reduce(function (r, a) {
if (!r || r[0].length < a.length) {
return [a];
}
if (r[0].length === a.length) {
r.push(a);
}
return r;
}, undefined);
}
function notInSequence(array, getValue = v => v) {
var longest = longestSequences(array, getValue);
return array.filter((i => a => a !== longest[0][i] || !++i)(0));
}
var array = [7, 3, 4, 4, 5, 1, 23, 7, 8, 15, 9, 2, 12, 13],
fDates = [['2015-02-03', 'name1'], ['2015-02-04', 'nameg'], ['2015-02-04', 'name5'], ['2015-02-05', 'nameh'], ['1929-03-12', 'name4'], ['2023-07-01', 'name7'], ['2015-02-07', 'name0'], ['2015-02-08', 'nameh'], ['2015-02-15', 'namex'], ['2015-02-09', 'namew'], ['1980-12-23', 'name2'], ['2015-02-12', 'namen'], ['2015-02-13', 'named']],
usuallyFailingButNotHere = [['2015-01-01'], ['2014-01-01'], ['2015-01-02'], ['2014-01-02'], ['2015-01-03'], ['2014-01-03'], ['2014-01-04'], ['2015-01-04'], ['2014-01-05'], ['2014-01-06'], ['2014-01-07'], ['2014-01-08'], ['2014-01-09'], ['2014-01-10'], ['2014-01-11']],
test2 = [['1975-01-01'], ['2015-02-03'], ['2015-02-04'], ['2015-02-04'], ['2015-02-05'], ['1929-03-12'], ['2023-07-01'], ['2015-02-07'], ['2015-02-08']];
console.log(longestSequences(array));
console.log(notInSequence(array));
console.log(notInSequence(fDates, a => a[0]));
console.log(longestSequences(usuallyFailingButNotHere, a => a[0]));
console.log(notInSequence(usuallyFailingButNotHere, a => a[0]));
console.log(longestSequences(test2, a => a[0]));
console.log(notInSequence(test2, a => a[0]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This solution uses the function reduce and keeps the previously accepted date to make the necessary comparisons.
var fDates = [['2015-02-03', 'name1'], ['2015-02-04', 'nameg'], ['2015-02-04', 'name5'], ['2015-02-05', 'nameh'], ['1929-03-12', 'name4'], ['2023-07-01', 'name7'], ['2015-02-07', 'name0'], ['2015-02-08', 'nameh'], ['2015-02-15', 'namex'], ['2015-02-09', 'namew'], ['1980-12-23', 'name2'], ['2015-02-12', 'namen'], ['2015-02-13', 'named']],
results = fDates.reduce((acc, c, i, arr) => {
/*
* This function finds a potential valid sequence.
* Basically, will check if any next valid sequence is
* ahead from the passed controlDate.
*/
function sequenceAhead(controlDate) {
for (var j = i + 1; j < arr.length; j++) {
let [dt] = arr[j];
//The controlDate is invalid because at least a forward date is in conflict with its sequence.
if (dt > acc.previous && dt < controlDate) return true;
}
//The controlDate is valid because forward dates don't conflict with its sequence.
return false;
}
let [date] = c; //Current date in this iteration.
if (i > 0) { // If this is not the first iteration
if (date === acc.previous) return acc; // Same as previous date are skipped.
// If the current date is lesser than previous then is out of sequence.
// Or if there is at least valid sequence ahead.
if (date < acc.previous || sequenceAhead(date)) acc.results.push(c);
else acc.previous = date; // Else, this current date is in sequence.
}
else acc.previous = date; // Else, set the first date.
return acc;
}, { 'results': [] }).results;
console.log(results);
.as-console-wrapper { max-height: 100% !important; top: 0; }
All of previous answers focus on JavaScript and maybe they won't work
correctly. So I decided to add new answer that focused on
Algorithm.
As #Trees4theForest mentioned in his question and comments, he is looking for a solution for Longest Increase Subsequence and out of order dates are dates that aren't in Longest Increase Subsequence (LIS) set.
I used this method like below. In algorithm's point of view, it's true.
function longestIncreasingSequence(arr, strict) {
var index = 0,
indexWalker,
longestIncreasingSequence,
i,
il,
j;
// start by putting a reference to the first entry of the array in the sequence
indexWalker = [index];
// Then walk through the array using the following methodolgy to find the index of the final term in the longestIncreasing and
// a sequence (which may need altering later) which probably, roughly increases towards it - http://en.wikipedia.org/wiki/Longest_increasing_subsequence#Efficient_algorithms
for (i = 1, il = arr.length; i < il; i++) {
if (arr[i] < arr[indexWalker[index]]) {
// if the value is smaller than the last value referenced in the walker put it in place of the first item larger than it in the walker
for (j = 0; j <= index; j++) {
// As well as being smaller than the stored value we must either
// - be checking against the first entry
// - not be in strict mode, so equality is ok
// - be larger than the previous entry
if (arr[i] < arr[indexWalker[j]] && (!strict || !j || arr[i] > arr[indexWalker[j - 1]])) {
indexWalker[j] = i;
break;
}
}
// If the value is greater than [or equal when not in strict mode) as the last in the walker append to the walker
} else if (arr[i] > arr[indexWalker[index]] || (arr[i] === arr[indexWalker[index]] && !strict)) {
indexWalker[++index] = i;
}
}
// Create an empty array to store the sequence and write the final term in the sequence to it
longestIncreasingSequence = new Array(index + 1);
longestIncreasingSequence[index] = arr[indexWalker[index]];
// Work backwards through the provisional indexes stored in indexWalker checking for consistency
for (i = index - 1; i >= 0; i--) {
// If the index stored is smaller than the last one it's valid to use its corresponding value in the sequence... so we do
if (indexWalker[i] < indexWalker[i + 1]) {
longestIncreasingSequence[i] = arr[indexWalker[i]];
// Otherwise we need to work backwards from the last entry in the sequence and find a value smaller than the last entry
// but bigger than the value at i (this must be possible because of the way we constructed the indexWalker array)
} else {
for (j = indexWalker[i + 1] - 1; j >= 0; j--) {
if ((strict && arr[j] > arr[indexWalker[i]] && arr[j] < arr[indexWalker[i + 1]]) ||
(!strict && arr[j] >= arr[indexWalker[i]] && arr[j] <= arr[indexWalker[i + 1]])) {
longestIncreasingSequence[i] = arr[j];
indexWalker[i] = j;
break;
}
}
}
}
return longestIncreasingSequence;
}
With method above, we can find dates that is out of order like below:
// Finding Longest Increase Subsequence (LIS) set
var _longestIncreasingSequence = longestIncreasingSequence(fDates.map(([date]) => date));
// Out of order dates
var result = fDates.filter(([date]) => !_longestIncreasingSequence.includes(date));
Online demo(jsFiddle)
here is a simple self- explanatory solution. hope it will help you.
const findOutOfSequenceDates = items => {
items = items.map(d => d);
const sequence = [], outOfsequence = [];
sequence.push(items.shift());
const last = ind => sequence[sequence.length - ind][0];
items.forEach(item => {
const current = new Date(item[0]);
if (current >= new Date(last(1))) {
sequence.push(item);
} else if (current >= new Date(last(2))) {
outOfsequence.push(sequence.pop());
sequence.push(item);
} else {
outOfsequence.push(item);
}
});
return outOfsequence;
};
var fDates = [
['2015-02-03', 'name1'],
['2015-02-04', 'nameg'],
['2015-02-04', 'name5'],
['2015-02-05', 'nameh'],
['1929-03-12', 'name4'],
['2023-07-01', 'name7'],
['2015-02-07', 'name0'],
['2015-02-08', 'nameh'],
['2015-02-15', 'namex'],
['2015-02-09', 'namew'],
['1980-12-23', 'name2'],
['2015-02-12', 'namen'],
['2015-02-13', 'named'],
];
console.log(findOutOfSequenceDates(fDates));
Use the Javascript Date type. Compare with those objects. Very simplistically,
date1 = new Date(fDates[i, 0])
date2 = new Date(fDates[i+1, 0])
if (date2 < date1) { // or whatever comparison you want ...
// flag / print / alert the date
}
To clarify, This merely finds items out of sequence. You can do that with strings, as Jaromanda X pointed out. However, you use the phrase "way out of line"; whatever this means for you, Date should give you the ability to determine and test for it. For instance, is '2023-07-01' unacceptable because it's 8 years away, or simply because it's out of order with the 2015 dates? You might want some comparison to a simpler time span, such as one month, where your comparison will looks something like
if (date2-date1 > one_month)
Summary of your question
If I have understood your question correctly, you are trying to identify array entries that do not follow a chronological order based on the time/date property value.
Solution
Convert the date string / time into a UNIX time stamp (number of seconds lapsed since 01/jan/1970 at 00:00:00)
Using a loop, we can store the value against a previous reading per itenary, if the value is negative, this would indicate an error in the date lapse, if the value is positive, it would indicate the order is valid
When negative, we can create an array to denote the position of the reference array and its values allowing you to go back to the original array and review the data.
Example Code
var arrData = [
{date: '2015-02-03', value:'name1'},
{date: '2015-02-04', value:'nameg'},
{date: '2015-02-04', value:'name5'},
{date: '2015-02-05', value:'nameh'},
{date: '1929-03-12', value:'name4'},
{date: '2023-07-01', value:'name7'},
{date: '2015-02-07', value:'name0'},
{date: '2015-02-08', value:'nameh'},
{date: '2015-02-15', value:'namex'},
{date: '2015-02-09', value:'namew'},
{date: '1980-12-23', value:'name2'},
{date: '2015-02-12', value:'namen'},
{date: '2015-02-13', value:'named'}
];
var arrSeqErrors = [];
function funTestDates(){
var intLastValue = 0, intUnixDate =0;
for (x = 0; x <= arrData.length-1; x++){
intUnixDate = Date.parse(arrData[x].date)/1000;
var intResult = intUnixDate - intLastValue;
if (intResult < 0){
console.log("initeneration: " + x + " is out of sequence");
arrSeqErrors.push (arrData[x]);
}
intLastValue = intResult;
}
console.log("Items out of sequence are:");
console.log(arrSeqErrors);
}
funTestDates();

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.

Categories

Resources